반응형

http://blog.naver.com/potheymd/50149717902

매트랩 기초 2.5 - 파일 읽기와 쓰기

매트랩 기초, 매트랩, 매틀랩, 매틀랩기초, 매트랩기초, Matlab, matlab, 수치해석, 수치해석기초

매트랩을 이용해서 데이터 파일을 읽고 쓰는 작업을 자주하게 되므로, 간단하면서도 효율적인 파일 조작에 대해 배워야 한다.


Load 함수

가장 간단한 파일 읽기 방법은 load 함수를 이용하는 것이다.

현재 작업 중인 디렉터리에 올려놓은 텍스트 첨부파일을 저장한다 ('inhaUpop.txt')

현재 작업중인 폴더에 저장되어있지않을경우 매트랩은 실행되지 않는다

대게 따로 정하지 않은 이상 MATLAB 폴더가 디폴트이며 현재 작업폴더를 다음과같이 도구창에서 확인가능하다.


'inhaUpop.txt' 에는 다음과 같이 네 줄의 데이터가 동일한 형식으로 저장되어있다.

2003 17027

2004 17505

2005 17698

2006 17832

'inhaUpop.txt'는 2003년부터 2006년까지 인하대학교 학부생 수를 나타내고 있다. 첫번째 열은 년도, 두번째 열은 총 학생 수이다.

'inhaUpop.txt' 를 읽기위해 명령 프롬프트에서 load 명령을 실행한다.

>> load 'inhaUpop.txt'

명령을 실행한 뒤에 명령창에는 별다른 내용이 표시되지 않는다.

이 상태에서 who 명령을 수행하면 현재까지 생성된 변수 외에 새로이 inhaUpop가 만들어 졌음을 알 수 있다

변수 inhaUpop의 내용은 아래와 같이 확인 가능하다

>> inhaUpop


inhaUpop =


2003 17027

2004 17505

2005 17698

2006 17832

이처럼 load 명령을 사용해 읽은 데이터 파일은 파일의 확장자를 제외한 이름의 변수에 그 내용이 저장된다.

그러므로 다음과 같이 변수 이름 inhaUpop를 이용해 그래프를 그릴 수 있다.

>> plot(inhaUpop(:,1),inhaUpop(:,2),'o:')




fscanf 함수

파일을 읽는 방법으로 load보다 다양한 기능과 옵션을 가진 함수는 fscanf이다. fscanf의 사용법은 다음과 같다

  • 여기서 fid는 파일 ID의 의미로 읽은 파일에 붙여지는 ID로 해석하면 된다.
  • format은 데이터 형식을 설정해주는 부분이다. fprintf처럼 %d와 %f 등을 사용한다.
  • size는 데이터의 크기를 배열 크기처럼 [mXn]으로 정해주는 것이다.

fscanf 함수의 리턴값은 두개인데, 대부분 count없이 a만 명시한다.

결과로 저장된 데이터는 행렬 a로 리턴되고, count 는 성공적으로 읽은 데이터 개수를 말한다.


그런데, 작업 대상인 데이터 파일의 fid를 얻기 위해서는 먼저 fopen 을 사용해 파일을 열어야 한다. fopen의 일반적인 사용법은 다음과같다.


fid = fopen (Filename, Permission)

  • 여기서 Filename은 읽고자 하는 파일 이름을 의미한다
  • Permission은 읽는 파일에 대해 허용된 기능을 의미한다.

일반적으로 읽기(read)만 하고 수정 혹은 첨부하지 않을 때는 'r'을 선택한다. 가능한 permission의 옵션을 보려면 help fopen을 사용한다.


다음 명령으로 inhaUpop.txt의 fid를 부여받을 수 있다.

>> fid = fopen ('inhaUpop.txt','r')


fid =


3

만약 ()안에 명시한 파일이 존재하지 않을 때는 fid가 -1로 반환된다.

앞의 명령으로 부여받은 fid로 inhaUpop.txt를 배열 a로 저장하는 방법은 다음과 같다.

>> [a,count]=fscanf(fid,'%d%d',[2 4])


a =


2003 2004 2005 2006

17027 17505 17698 17832



count =


8

위의 명령에서 size에 해당하는 [2 4]에 주의해야한다.

fscanf명령은 열(column)-행(row) 순서로 데이터 파일을 읽기 때문에 열의 개수를 먼저 명시해야 한다.

inhaUpop.txt는 두개의 열과 네개의 행으로 되어있으므로 [2 4]로 size를 정했다.

만약 읽어들이는 데이터 파일의 열의 개수는 알지만 행의 개수가 많아서 구태여 개수를 세어 값을 정하지 않기 위해서는

행의 수에 inf를 사용한다. 즉 데이터 파일이 2개의 열로 구성되었다면 size 부분에 [2 inf]를 쓴다.


fscanf의 결과로 저장된 a 행렬은 실제 데이터 파일 형태의 전치행렬이다. 따라서 다음과 같이 a 행렬을 전치시켜 사용하는 것이 일반적인 방법이다.

전치된 행렬을 사용해 load 로 읽어 그린 그래프와 동일한 그래프를 그릴 수 있다.

>> a= a'


a =


2003 17027

2004 17505

2005 17698

2006 17832


>> plot(a(:,1),a(:,2),'o:')


예제의 경우에는 열린 파일 inhaUpop.txt를 닫을필요는 없지만 매트랩 프로그램이 복잡해질수록,

작업이 종료된 파일은 닫아주는 것이 좋다. 열린 파일을 fid를 이용해 닫는 방법은 다음과 같다

fclose(fid);

만약 여러개의 파일이 열려있는 상태라면 한 번의 명령으로 모든 파일을 닫는 것이 편ㄹ하다.

이 경우는 fclose all; 을 사용한다.


반응형
반응형

http://blog.naver.com/potheymd/50149714027

매트랩 기초 2.3 - 벡터화 (vectorization)

for문은 쉽게 구현할 수 있고 이해하기도 쉽다는 장점이 있지만, 매트렙에서 특정한 작업을 반복하는 데 있어 효율적인 방법은 아니다.

매트랩은 행렬을 대상으로 직접 연산이 가능하기 때문에 벡터화가 훨씬 더 효율적이다.

예를 들어 다음 프로그램을 살펴보자.

j=0;

>> for t = 0: 0.01:40

j=j+1;

y(j)= cos(t);

end

이 프로그램은 4001개의 t값을 생성하고 각 t의 cosine 값을 y벡터에 저장한다.

이 과정을 다음과 같이 벡터화 프로그램으로 변환할 수 있다.

t= 0:0.01:40;

y=cos(t);

벡터화 프로그래밍으로 생성한 y 벡터는 위에서 작성한 일반 프로그래밍 기법보다 효율성이 우수하고 처리 속도도 빠르다.

매트랩 프로그램은 가능한 경우 벡터화를 하는 것이 좋다.



매트랩 기초 2.3 - 메모리할당

매트랩은 배열에 새로운 원소를 할당할 때마다, 배열의 크기를 자동적으로 늘리도록 설계되어있다.

이러한 이유 때문에 만약 루프구조에서 매번 배열의 원소를 하나씩 늘려간다면, 상당한 시간이 소요된다.

예를 들어 다음과 같은 프로그램을 살펴보자.

>> t=0:0.01:5;

for j=1:length(t)

if t(j)>1

y(j)=1/t(j);

else

y(j)=1;

end

end

이 경우 매트랩은 배열 y의 크기는 새로운 값이 대입될 때 마다 바뀌게 된다.

배열의 크기가 매번 변경되면서 메모리 크기도 같이 조정되어야 하므로 당연히 비효율적인 프로그램이 된다.

이런 비효율성을 피하기 위해 아래와 같이 미리 사용하고자 하는 배열의 크기를 정해, 루프가 반복되더라도 메모리 크기가 변하지 않게 해야한다.

>> t=0:0.01:5;

y=ones(length(t),1);

for j=1:length(t)

if t(j)>1

y(j)=1/t(j);

else

y(j)=1;

end

end

반응형
반응형

http://blog.naver.com/potheymd/50149488346 에서 일부 발췌

사용자가 원하는 가로 및 세로축의 범위를 정하기 위해서는 axis 명령어를 사용할 수 있다.


한 페이지에 그림을 두 장 같이 그릴 경우에는 subplot 명령어를 사용하면 된다.

subplot은 주어진 페이지를 행렬처럼 분할한다.

예를 들어보자

>> subplot(2,1,1)

>> plot(t,sin(t))

>> axis([0 2*pi -1. 1.])

>> ylabel('Sine')

>> title('Sine Function')


>> subplot(2,1,2)

>> plot(t,cos(t))

>> axis([0 2*pi -1. 1.])

>> title('Cosine Function')

>> ylabel('Cosine')

>> xlabel('Values of t')

예로 든 (2,1,1)은 2X1행렬의 첫 원소처럼 공간이 할당되는 셈이다. 따라서 하단의 그림은 두 번째 원소 (2,1,1)처럼 공간을 차지한다.


따라서 그래프는 다음과 같이 그려진다.

반응형
반응형

http://blog.naver.com/potheymd/50149488346

plot함수는 그래프에서 사용되는 기호와 선의 모양을 다양하게 선택할 수 있다.

아래의 표는 몇가지 중요한 선택사양을 설명하고 있다.

심벌

Blue

b

point

.

solid

-

Green

g

Circle

o

Dotted

:

Red

r

X

x

Dashdot

-.

Cyan

c

Plus

+

Dashed

--

Margenta

m

Star

Yellow

y

Square

s

Black

k

Diamond

d

Triangle(down)

v

Triangle(up)

^

Triangle(left)

<

Triangle(right)

>

Pentagram

p

Hexagram

h


위의 선택사항과 라벨 등을 붙인 예는 다음 아래의 그림과 같다.

>> t=0:0.1:2*pi;

>> plot(t,sin(t))

>> plot(t,sin(t),'d')

>> xlabel('Values of t')

>> ylabel('Sine')

>> title('Sine function')

>> grid  

반응형
반응형

매트랩 복소수 문자 배열등등 첨부 --> pdf 파일

http://164.125.37.225/~dhlee/wiki/images/3/37/AM10-lect08-4s.pdf 에서 다운

반응형
반응형

http://engi-agora.tistory.com/8

Matlab / 매트랩] 매트랩 강의 5번째

5. 3차원 그래프 그리기 (3D graph)

이미 매트랩으로 2차원 그래프는 어느정도 그릴 수 있으리라 생각하고, 이제 3차원으로 슬슬 눈을 돌릴때가 되지 않았나 싶네요.

후후, 그렇습니다. 오늘은 드디어 3차원 그래프를 다뤄볼 그 시간입니다 !!!!

2차원 그래프는 다음과 같은 X,Y의 데이터 세트를 한 그래프에 나타내는 것이었습니다.

2차원 그래프를 그리기 위해서는 X, Y의 세트가 필요했지만

3차원 그래프를 그리기 위해서는 당연히 데이터 세트가 3개가 필요할 것입니다.

X , Y, Z 이렇게 바로 3개로 말이죠!!

이때 X Y Z가 나타날 수 있는 방법은 크게 2가지 경우가 있을 수 있겠는데요.

첫째는 X Y Z 가 하나의 데이터가 independent 한 경우이고,
두번째는 X Y Z에서 두개의 데이터가 independent 한 경우입니다.

일부러 말을 좀 어렵게 써봤습니다....는 아니고ㅠ 뭐 그래요.
쉽게 풀어서 쓰자면 첫번째 경우는 Y Z가 모두 X로 표현되는 경우이고
두번째 경우는 Z가 X,Y로 표현되는 경우
지만, X Y는 서로 관계가 없는 경우를 뜻합니다.

첫번째 경우와 두번째 경우의 각각 예를 들어 볼게요.

1) 첫번째 경우의 예
Y=X*3
Z=X^2+X+2
(X는 실수집합)

2) 두번째 경우의 예
Z=X^2 + Y^2
(X, Y 는 실수집합)

흐흐 오늘은 뭔가 설명이 쉽게 안되는것 같군요.....흑ㅠ

그래프로 차이를 보여 드리도록 할게요.

1) 첫번째 경우같은 그래프는 다음과 같은 형태로 표현됩니다: (아, 위의 예와는 다른 식입니다.)

2) 두번째 경우의 그래프는 다음과 같은 형태로 표현됩니다: ( 마찬가지로 위의 예와는 다른 식입니다. 유의)

그래프로 보시니 조금 감이 오실듯 하나요??

즉, 첫번째 경우는 X가 바뀌는데 따라서 Y도 바뀌고 Z도 바뀌니깐
X가 하나로 결정되면 Y,Z도 하나로 결정된다는 의미입니다.
예를 들어 X가 1이라면 Y는 2, Z는 3, 이런형태로 반드시 하나만 나오게 됩니다.

반면에 두번째 경우는 X가 하나로 결정되도 Y는 어떤 값이든 가질 수 있게 됩니다.
예를 들어 X가 1이라도 Y는 1일수도 2일수도 3일 수도 ...... 모든 값을 가질 수 있다는 말이죠.
그래서 두번째 경우는 X의 값이 하나로 결정되더라도 Y의 값이 여러개가 존재하므로 면과 같은 형태의 그래프가 나오고
첫번째 경우는 선과 같은 형태의 그래프가 나오게 되는 것입니다.

요렇게 두개로 구분한 이유는!!
사실 이 두개의 경우에 따라 그래프를 그리는 명령어가 다르기 때문이에요.

첫번째 경우는 plot3 이란 함수를 쓰고 두번째 경우는 mesh라는 함수
를 씁니다.

차례대로 한번 예시를 들어보도록 하겠습니다.

1. 입력 변수가 1개인 경우 (명령어: plot3)

자, 이 경우 X,Y,Z는 무조건 하나의 변수로 정의가 되어야 합니다.

예를들어 모두 X로 표시가 된다든지,

X=[1:0.01:10];
Y=2.*X;
Z=3.*(X.^2)+6;

혹은 모두 Y로 표시가 된다든지,

Y=[1:0.01:10];
X=3.*Y
Z=X.^2+Y.^2;

(Z에서 X로 쓰였지만 결국 X는 Y로 표현되기 때문에 Z는 Y로만 표현된 것이라 볼 수 있습니다.)

혹은 임의의 t로 표시가 된다든지 해야 하는 것입니다.

t=[1:0.01:10];
X=3.*t;
Y=t.^3+2.*t
Z=3./t + 21.*t;

이런식으로 데이터 구조가 작성되었다면 그래프 그리는건 식은죽 먹기 입니다.
요렇게 나타내 주시면 끝나요.

plot3( X데이터, Y데이터 , Z데이터);

예를 하나 들어볼까요? 매트랩 help를 뒤적이시면 나오는 예입니다.
지금 이 경우는 t로 X,Y,Z데이터를 다 표현했습니다.

ex)
>> t = 0:pi/50:10*pi;
>> plot3(sin(t),cos(t),t);

이 경우에도 2차원 그래프 그릴때와 마찬가지로 옵션적용이 다 가능합니다. 물론 figure, hold on, subplot도 마찬가지로 다 먹히죠.

그래프를 빨간색 동그라미로 나타내고
제목을 달고,
x,y,z 라벨 표시
grid on

요 순서로 옵션 적용을 한번 해볼께요.

>> plot3(sin(t),cos(t),t,'ro')
>> title('3d graph');
>> xlabel('x axis')
>> ylabel('y axis')
>> zlabel('z axis')
>> grid on

네, 다 잘먹혀 들어가는 것을 보실수 있습니다. 참 쉽죠잉?

2. 입력 변수가 2개인 경우 (명령어: mesh)

이 경우는 데이터 구조가 이런식으로 주어지게 됩니다.

위에서 봤을 때의 데이터를(z11 z12 z13 z14 순서대로) X축의 데이터로
옆에서 봤을 때의 데이터를(z11 z21 z31 z41 순서대로) Y축의 데이터로 받아줍니다.

그리고 이때 X의 j번째,Y의 i번째에 해당하는 데이터 Z(i,j)가 그래프의 출력이 되는 셈입니다.
흠 말이 조금 어렵나요??

만일
Z=
[1 2 3 4 5
6 7 8 9 10
11 12 13 14 15]

로 주어졌다면, x축의 데이터는 5개, y축의 데이터는 3개가 되는 셈입니다.

이때, x범위를 만일 1 2 3 4 5// y 범위를 1 2 3 으로 지정한다면

x가 1, y가 2일 때는 z값은 6이라는 데이터를 내뱉어 준다 요런말이죠.

이런 경우일 때는 mesh 라는 명령어를 쓰는데요.

기본적으로 mesh는 요렇게 쓰입니다.

mesh(X 데이터, Y 데이터, Z 데이터)

문제는 요 Z 데이터라는 놈이 m by n 형태의 행렬로 입력이 되어야 한다는 거죠!!!!!!!

근데 여기서 잘 생각해 보셔야 할게 있습니다,

Z=X^2+Y^2 라는 식이 주어졌다고 하고, X범위가 1~3까지, Y범위가 1~5까지라고 합시다.

그럼 단순하게

x=[1:1:3];
y=[1:1:5];
z=x.^2+y.^2;

으로 한다면 z데이터가 행렬로 나올수가 있을까요????

절대로 아니겠죠. 일단 x, y의 범위 자체가 다르기 때문에 계산도 안될 뿐더러,

계산이 된다 하더라도 z는 벡터 값을 가지게 되어 절대로 처음에 원했던 결과가 나오지 않게 됩니다.

그럼 이를 해결하기 위해서는 어떻게 해야 할까요????

바로 x데이터와 y데이터 자체를 z데이터가 계산가능하도록 행렬로 변환해주어야 합니다.

즉 x가 1일 때, y값은 1~5 까지의 값을 모두 가질 수 있는 데이터 한 줄,
x가 2일때 y 값이 1~5까지 값을 모두 가질 수 있는 데이터 한 줄 이런식으로 바꿔져야 한다는 말이죠.

무슨말인지 잘 와닿지 않을 것이라 생각하고...... 일단 필요한 결과 행렬을 보여 드리겠습니다.

X=[1 2 3
1 2 3
1 2 3
1 2 3
1 2 3]

Y=[1 1 1
2 2 2
3 3 3
4 4 4
5 5 5]

이렇게 X, Y 가 행렬로 표시된다면 Z 는,

X가 1일때 Y가 1~5까지
X가 2일때 Y가 1~5까지
X가 3일때 Y가 1~5까지의

값을 모두 다 받아 줄 수 있게 되는 셈입니다.

근데 물론 이거 사람이 직접하면 매트랩 아무도 안쓰겠죠?

명령어 있습니다. 역시나!!!!!

[X데이터 ,Y데이터 ] = meshgrid(x범위, y범위)

요렇게 입력해주시면 되는 거에요.

그럼 위에서 나왔던 식을 한번 mesh를 이용해서 그려볼게요.

예제) Z=X^2+Y^2, X범위가 1~3까지, Y범위가 1~5까지일때의 그래프를 그려라.

>> x=[1:0.1:3];
>> y=[1:0.1:5];
>> [X Y]=meshgrid(x,y);
>> Z=X.^2+Y.^2;
>> mesh(X,Y,Z)

마찬가지로 title, xlabel, ylabel, axis([Xmin Xmax Ymin Ymax Zmin Zmax]) 등의 명령어는 물론 쓸 수 있습니다.

아, 그리고 명령어에 넣을 때, Z데이터는 행렬로 나와 줘야만 하지만, x,y는 행렬로 넣어줄 필요는 없습니다.

위의 예에서 mesh(x,y,Z)라고 해도 그래프는 똑같이 그려집니다!! 혹여나 햇갈리실까 하여....

오늘은 뭔가 설명히 딱딱한 느낌이네요ㅠ..가을타는가..........흑ㅠ
다음엔 재미있는 도형 그리기로 넘어가봅시다. 슬슬 난이도가 올라가는 느낌이 물씬 풍기네요ㅠ


반응형
반응형


[Matlab / 매트랩] 강의 3번째

2차원 그래프 그리기 (2D graph)

우왕ㅋ 굿ㅋ 번개같은 업뎃입니다!!!!!!.............(은)는 훼이크고

사실을 금욜날 3강까지 업뎃할 예정이었습니다... 흐흑ㅠ 이미 한참 지나버렸네요 흐흑ㅠ

어찌되었건 은근슬쩍 넘어가서 이번부터는 그래프 그리는걸 한번 배워보도록 해요.

그래프는 2차원 그래프 그리기, 3차원 그래프 그리기, 도형 그리기 요렇게 3 파트로 나눠서 해볼까 하는데

오늘은 먼저 2차원 그래프 그리는 것 부터 해볼까 합니다.

요런 2차원 그래프도 표현이 당연히! 가능합니다.

후후 아름답군요. 엘레강스합니다.

위에 나온 그래프 중에서 가장 빈티나는(...) 2차원 그래프부터 그려보는 걸 한번 해볼까 하는데요.

그래프 그리는 순서는 다음과 같습니다.

1) x축 데이터 정하기(벡터로 표현).
2) y값을 x 값을 이용하여 나타내기.
3) plot명령어를 사용하여 그리기.
4) 추가적인 옵션(그래프 색, grid, x,y이름표 붙이기, 그래프 이름, 범례 표시 등등)

주로 제가 사용하는 방법은 위의 형식입니다. 물론 다른 방법도 있습니다만...! 하나하나 차근히 해보도록 해요.

일단 예를 한번 들어보겠습니다.

y=3*x 그래프를 그려보도록 하겠습니다.

1) x 데이터 지정하기(벡터로 표현)

그리고자 하는 x축 범위를 예를 들어 -3~3 까지 나타내고 싶다고 합시다.
이때 주의할 점은 x축 데이터를 벡터로 표현해야 한다는 것입니다.

왜냐고요?

매트랩이 그래프를 그려주는 원리를 일단 설명을 해야 할 것 같네요.

매트랩이 2차원 그래프를 그리기 위해선 데이터가 2 세트가 필요합니다.

x 데이터와 그에 대응하는 y 데이터죠.

예를 들어 x = [ 1 2 3 4 5] 라는 데이터가 있고
y=[2 4 6 8 10] 이라는 데이터가 있다면

x의 첫번째 데이터와 y의 첫번째 데이터를 하나의 세트로 생각해서 (1,2)를 그래프에 나타내줍니다.
마찬가지로
x의 두번째 데이터와 y의 두번째 데이터를 하나의 세트로 생각해서 (2,4)를 그래프에 나타내줍니다.
역시나 마찬가지로 (3,6),(4,8),(5,10)을 그래프에 찍어주는 형태입니다.

즉, x데이터와 y의 데이터를 순서대로 1:1 대응을 시켜서 그래프를 그려주는거죠.

따라서 x 데이터와 y의 데이터는 벡터의 형태 (1,m 크기의 행렬)로 표시되어야 하며, 두개의 크기가 같아야 합니다.

물론 위의 경우는 점으로 표시되지만, plot명령어를 쓰게되면 그 사이를 선으로 연결시켜 줍니다.

직접 매트랩 명령어와 그래프를 보여 드릴게요.
x와 y를 벡터로 나타낸 다음, plot이란 명령어를 썼습니다.

>> x=[1 2 3 4 5];
>> y=[2 4 6 8 10];
>> plot(x,y)



네 요렇게 나와주시는걸 볼 수 있습니다.

기본적으로 plot명령어는 파란색 선으로 그려주기 때문에 위와 같이 나타나지만 다르게도 표현할 수 있습니다.

자, 여튼 데이터를 나타내기 위해서 벡터 형식으로 나타내야 한다는 것은 아시겠죠?

그런데, -3~3 까지 그리기 위해서 벡터형식으로 나타내려면 숫자를 일일이 쳐줘야 한다는 단점이 있습니다.

x=[-3 -2.99 -2.98 ..... 2.99 3]

요런식으로 둬야 하는데 말이죠.

하지만 현실적으로 일일이 칠 수가 없기 때문에!! 바로 입력하는 방법이 있습니다. 바로 요렇게 말이죠.

x=[시작 값 : 데이터 하나당 크기 : 끝값]

예를 들어 볼게요.

>> x=[-3: 1: 3]

x =
-3 -2 -1 0 1 2 3

쉽죠? -3에서 3까지 1의 단위로 벡터를(혹은 행렬을) 만들어 줘라는 의미가 됩니다.

위에서 x데이터와 y의 데이터를 1:1대응을 해서 나타낸다고 했으므로, 데이터가 촘촘할수록 더 정확한 그래프가 그려지겠죠?

y=3*x를 나타내기 위해 여기선 x의 범위를 -3에서 3까지 0.01씩 지정할게요.

>> x=[-3:0.01:3];


2) y값을 x 값을 이용하여 나타내기

y=3*x의 그래프를 그리고 싶습니다. x는 벡터로 지정되었기 때문에, 이제는 y를 벡터로 지정해줄 차례입니다.

단순히
>> y=3*x;

요렇게 쳐도 괜찮습니다만, 요전 앞 강의에서 행렬의 성분마다 계산!!! 을 하기 위해서는 점!! '.' 을 찍어야 한다는 것. 잊지 않으셨죠?

위의 경우는 숫자 곱하기 벡터라는 단순한 상황이기 때문에 위의 명령어도 먹혀 들어가지만,

2차 그래프나 3차그래프, 분수 등의 다른 형태가 나오게 되면 안되는 경우가 태반이기 때문에,
항상 점 '.'을 찍어주시는 것을 습관화합시다.

즉 요렇게 저는 칠께요.

>> y=3.*x;

이렇게 되면, y는 x라는 벡터에 3을 곱한 결과를 가지는 벡터가 되는 것입니다.

3) plot명령어를 사용하여 그리기
앞에서 이미 설명을 해버렸지만, plot(x,y) 이라는 명령어를 쓰면 x 데이터와 y 데이터를 1:1 대응을 시켜서 그래프를 매트랩이 알아서 그려주게 됩니다. 요렇게 입력해주면 되겠죠?

>>plot(x,y)

여기까지 하면 이런 그래프가 나오게 됩니다.
>> x=[-3:0.01:3];
>> y=3.*x;
>> plot(x,y)

[축하드립니다!! 그래프 그리기 기본 스킬을 습득하셨습니다.]

여기까지 하면 그래프 그리기는 사실상 99% 정도는 끝난거지요.

이제 여기서 그래프를 스리슬쩍 꾸미면 2차원 그래프는 완성되게 됩니다.

4) 추가적인 옵션(그래프 색, grid, x,y이름표 붙이기, 그래프 이름, 범례 표시 등등)

살짜쿵 위의 그래프를 꾸며볼까요? 일단 색깔과 형태를 바꿔 볼게요.
명령어는 다음과 같습니다.
plot(x,y,'색깔')
색깔 부분에는 빨간색이면 'r' 초록색은 'g' 노란색을 'y'등으로 나타낼 수 있어요. 한번 빨간색으로 해볼께요.

>> plot(x,y,'r')

쉽죠? 형태도 바꿀 수 있습니다. 점이나 +, 사각형, 원 등으로 표현할 수도 있어요. 색깔 치는 부분에 형태에 관한 명령어나, '색깔,형태'의 형식으로 나타내주면 됩니다. 한번 보여 드릴게요.
(형태에 관한 명령어 점 -> . 사각형 ->s 원->o 등등. help plot을 치면 쉽게 알 수 있습니다.)

>> plot(x,y,'ro')

데이터 개수가 많아서 원이 겹쳐 굵은 선으로 보이는 군요. 데이터 개수가 적으면 원으로 보입니다 하핫

다음은 다른 옵션들을 적용해볼게요. 순서대로 적용하겠습니다.

x축 이름 표시 (xlabel('이름'))
y축 이름 표시 (ylabel('이름'))
그래프 제목 표시 (title('이름'))
경계 조절(그래프 나타낼 범위 조절) (axis([x최소 x최대 y최소 y최대])
그리드 표시 (grid on)

>> xlabel('x axis')
>> ylabel('y axis')
>> title('graph')
>> axis([-2 2 -8 8])
>> grid on


여러가지 옵션들이 적용된 것을 볼 수 있죠?





ref http://engi-agora.tistory.com/6 에서 일부 발췌

반응형
반응형



매트랩(MATLAB) 프로그램은 미국의 The Mathworks Incc 에서 만든 과학기술 분석 프로그램으로 기존의 프로그래밍 언어보다 훨씬 쉽게 배우고 사용할 수 있다. MATLAB은 MATrix LABoratory의 약자로 알려져 있으며, 그 의미는 모든 연산을 벡터(vector)기반으로 행렬(matrix)처럼 처리한다는 것이다.

현재는 업그래이드 버전이 나와있으나, 여기서는 버전 6.1을 사용한다. 버전 7.1과 6.1은 기능면에서 크게 차이나지 않는다.

1.1 매트랩 기초중의 기초!

매트랩 프로그램을 실행하면 아래와 같은 명령 프롬프트(command prompt)가 생성된다.


가장 간단한 매트랩 사용법으로 다음과 같이 사용할 수 있다.


>>77 - 66


그 결과는 다음과 같이 출력된다.


ans=

11


위의 경우와 같이 매트랩은 항상 그 결과 값을 ans 라는 변수에 저장한다. 그러므로 다음 프롬포트에서 ans 라는 변수를 바로 사용할 수도 있다.

>> ans +22

ans =

33

위처럼 출력된다. 위와같이 매트랩은 사용자가 별도의 변수에 결과 값을 저장하지 않을 경우 디폴트(default)로 ans 변수를 사용한다.


벡터가 아닌 스칼라(scalar) 값을 사용자가 선택한 변수 a 에 저장하는 방법은 다음과 같다

>> a = 11

이 경우 다음과 같이 화면에 출력된다.

a=

11


만약 연산의 결과를 화면에 출력하고 싶지 않을 경우에는 세미콜론(;)을 사용하면 된다.

>>A = 22;

여기에서 소문자 a와 대문자 A는 전혀 다른 변수이다. 다시말해 매트랩에서 사용하는 변수는 case-sensitive이다.

여러개의 대입문 혹은 명령문을 한 줄에 처리할 수도 있는데, 이 경우에는 각각의 문자을 콤마(,)로 분리한다.

>>a=11, A= 22;

그 결과는 다음과 같이 출력된다.

a=

11

*A는 뒤에 세미콜론(;)이 붙었기 때문에 화면에 출력되지 않는다!


who라는 명령어의 사용법도 기억해 둘 필요가 있다.

who명령어는 현재 메모리에 저장된 변수명을 보여준다.

예를 들어 매트랩을 시작한 이후 지금까지 예제로 보여준 명령만을 실행하였다고 가정하고 who 명령을 시행할 경우 아래와 같이 출력된다.

>>who

Your variables are:

A a ans

즉 지금까지 사용한 변수 A와 a, 그리고 앞부분의 연산 결과인 33이 ans 변수로 저장되어 있음을 확인할 수 있다.

그리고 각 변수에 저장되어 있는 값을 확인하려면 명령 프롬프트에서 그 변수명을 입력하면 된다.

예를 들어 A에 저장된 값이 무엇인지 알고 싶다면 아래와 같이 할 수 있다.

>>A

A=

22


이미 매트랩에서 정의된 변수들이 있는데, 예를 들어 pi를 다음과 같이 사용할 수 있다.

>>pi

ans =

3.1416

이처럼 매트랩은 디폴트로 소수점 이하 4자리 까지 표시한다.


만약 더 많은 소수이하자리수를 보여주고자 할 때에는 format long 을 사용하면 된다.

long의 경우에는

>>pi

ans=

3.14149265358979

이를 다시 디폴트로 되돌리려면

>>format short

를 이용해주면 된다.


help (원하는 명령어) 를 이용하면 비교적 상세한 명령어 사용법을 배울 수 있다.

예를들어 format 명령어에 대하여 더 상세한 설명과 옵션을 알고싶다면 help format 을 입력하면되고 다음과 같이 실행된다.




ref : http://blog.naver.com/potheymd/50149480337

반응형
반응형

http://cafe.naver.com/mhjune/31


MATLAB의 기본

그래프(2D)

>> plot([1 2 3],[4 5 6])

(commend 창에 치세요)

>> (xlabel('시간'))

>> (ylabel('속도'))

그래프에 눈금을 넣어주는것 >>grid

제목 넣어주는 것 title(' ')

선의 모양 및 색깔 넣어주는 것 plot([ ],[ ],[' '])

':' , '-.' , '--' , '--r' , '*k' 등등

plot([1 2 3],[4 5 6],['--r'])

이제부터 한 그래프안에 여러개의 그래프를 넣는 방법

plot([1 2 3],[4 5 6 ],['-r'],[1 2 3],[8 9 10],['--b'], [1 2 3],[1 2 3],[':k'])

그래프안에 선의 이름을 정해 주는 것

legend('x1-date','x2-date','x3-date')

경우에 따라 그래프를 겹쳐야 할때도 있고 뺄때도 있으므로 이럴땐

이런 방법을 사용함

>> plot([1 2 3],[4 5 6],['--r'])

>> hold on

>> plot([1 2 3],[8 9 10],['-b'])

>> hold on

해제를 시킬 경우는

>> hold off

>> plot([1 2 3],[8 9 10],['-b'])

>>

그래프를 별도의 figure에 해야 될 경우

>> figure(1)

>>

>> plot([1 2 3],[1 2 3],['*b'])

>> figure(1)

이 figure(1)에 대한 그래프가 나오고

>> figure(2)

>>

>> plot([1 2 3],[1 2 3],['--b'])

>> figure(2)

이 figure(1)에 대한 그래프가 나옵니다.


하나의 figure에 안에 따로 따로 모았을 경우

>> subplot(221)

>> plot([1 2 3],[1 2 3],['--b'])

>> subplot(222)

>> plot([1 2 3],[4 5 6],['-b'])

>> subplot(223)

>> plot([1 2 3],[8 9 10],['*b'])

>> subplot(224)

>> plot([1 2 3],[8 9 10],[':b'])



subplot(221)의 의미는

앞에 22는 행과 열의 의미이여 뒤에 1은 행과 열의 순서라고 보면 됩니다.

횡일때는 순서를 왼쪽에서 오른쪽으로 잡으며 종일때는 위에서 밑으로 합니다.


연습문제

>> t=[0:0.1:20+pi];

>> subplot(221)

>> plot(sin(t))

>> xlabel('t'),ylabel('sin(t)')

>> subplot(222)

>> plot(cos(t))

>> xlabel('t'),ylabel('cos(t)')

>> subplot(223)

>> syms t

>> ezplot(tan(t))

>> xlabel('t'),ylabel('tan(t)')

>> subplot(224)

>> ezplot(t)

>> xlabel('t'),ylabel('t')

>> figure(2)

>>

>> t=[0:0.1:20+pi];

>> plot(t.^2+2*t+1)

>> xlabel('t.^2+2*t+1'),ylabel('t')

>>

3D그래프 (축이 3개)

>> plot3([1 2 3 4],[5 6 7 8],[9 10 11 12])

>> x=[0:pi/50:pi];

>> y=[0:pi/50:pi];

>> z=sin(x)+cos(y);

>> plot3(x,y,z)

>> grid

>>

[삼차원]mesh:(y의 한지점을 기준으로 해서 x의 모든 경우의 수를 고려해서 그때의 축을 만들어줌)

함수를 만들기 전 meshgrid를 먼저 만들어 줘야 한다.

>> x=[0:pi/50:pi];

>> y=[0:pi/50:pi];

>> [X,Y]=meshgrid(x,y);

>> mesh(X,Y,sin(X)+cos(Y)) (삼차원 그래프가 등장)

>> surf(X,Y,sin(X)+cos(Y))(z의 값에 따라 색이 다름)


>> surfc(X,Y,sin(X)+cos(Y)) (2D+3D로 등곡선 표시)

>> colorbar(X,Y,sin(X)+cos(Y)) (값에 따른 색상 표시)


>> contour(X,Y,sin(X)+cos(Y)) (등곡선만 2차원으로 표시

반응형
반응형

pdf 파일


http://web.yonsei.ac.kr/hgjung/Ho%20Gi%20Jung%20Homepage/Lectures/2011%20Fall%20PME/2B%20MATLAB%20%EA%B8%B0%EC%B4%88%20%EC%82%AC%EC%9A%A9%EB%B2%95.pdf

반응형
반응형

블로그 이미지

3DMP engines

3D그래픽스 물리 수학, 프로그래밍 GPU Shader 게임엔진 알고리즘 디자인패턴 matlab etc.







회전사원수의 곱을 행렬로 만들다보면 X*Y*Z 또는 Z*Y*X 오일러 회전행렬을 곱한 순서가아니라는 것을 알수있다

회전사원수의 곱은 Z*X*Y 행렬 곱으로 나타난다





[왼손기준 = Z*X*Y 행렬 ]

{{cosz,sinz,0},{-sinz,cosz,0},{0,0,1}}*{{1,0,0},{0,cosx,sinx},{0,-sinx,cosx}}*{{cosy,0,-siny},{0,1,0},{siny,0,cosy}}

[오른손 기준 = Z*X*Y 행렬 ]




{{cosy,0,siny},{0,1,0},{-siny,0,cosy}}*{{1,0,0},{0,cosx,-sinx},{0,sinx,cosx}}*{{cosz,-sinz,0},{sinz,cosz,0},{0,0,1}}

반응형
반응형

블로그 이미지

3DMP engines

3D그래픽스 물리 수학, 프로그래밍 GPU Shader 게임엔진 알고리즘 디자인패턴 matlab etc.





구면선형보간함수를 구현하다보면 일반적인 벡터부분만 뽑아와 내적을 하는것이  DirectX 에서 제공하는 함수와 결과가

한번씩 반대로 나온다는것을 알 수 있다


그것을 아래 첨부한 내용과 같이 해결하면 된다






http://www.gpgstudy.com/forum/viewtopic.php?t=1949


내적이 0보다 작은 경우에 두 쿼터니온 중 하나의 부호와 내적결과의 부호를 반대로 해야한다

D3DX 의 slerp 함수는 이처럼 되어있음






반응형
반응형

http://www.gpgstudy.com/forum/viewtopic.php?p=121140

올리기

Re: D3DXMatrixTranspose용도는?

올려짐: 2009-06-26 01:54
인용과 함께 답변 이 게시물을 del.icio.us에 추가


비회원 씀:
D3DXMatrixTranspose이건 어느 상화에 쓰는건가요?

행과 열을 서로 바꾸는 걸 하나 본데 말이죠

그리고
d3dxmatrixinverse(&m,NULL,&mworld);
이러면 world좌표가 local좌표로 바뀌는건가요?

그럼 감사합니다



openGL의 경우 오른손 좌표계고 DirectX의 경우 왼손 좌표계 입니다.

openGL을 쓰다가 D3DX수학함수들이 쓰고 싶을때.. D3DX 함수로 계산한 행렬을 openGL에 적용시킬때는
D3DXMatrixTranspose해서 넘겨줘야겠죠.

그리고 쉐이더에서 전치행렬이 필요한경우가 있습니다. 이때도 Transpose를 쓰죠.

반응형
반응형

http://www.gpgstudy.com/forum/viewtopic.php?p=100599

왼손좌표계와 오른손좌표계 때문에 행렬이 전치관계를 갖는 것이 아니라
row-major이냐 column-major이냐에 따라 행렬이 전치관계를 갖고 행렬 곱셈 순서도 바뀝니다.

DirectX는 row-major이고 OpenGL은 column-major이니까 행렬도 전치해주고 곱셈 순서도 바뀌어야 합니다.

행렬의 row-major/column-major는 왼손좌표계/오른손좌표계와 독립적입니다.
예를 들어, nebula엔진이 row-major(DirectX)를 쓰고 오른손좌표계(OpenGL)을 사용하는 것으로 알고 있습니다.

반응형

'수학 (Mathematics) > 3D수학' 카테고리의 다른 글

구면선형보간의 핵심요소  (0) 2012.11.02
d3dx 수학 함수들을 opengl 에서 쓰고 싶을때  (0) 2012.11.02
짐벌락 피하는 방법  (0) 2012.11.02
쿼터니언  (0) 2012.11.02
광선추적 (Ray Tracing)  (0) 2012.11.02
반응형

[게임수학] 짐벌락과 쿼터니언 - 1 게임수학 / 개인

2012/08/30 13:15

복사http://blog.naver.com/qkfkf123/60170135935

짐벌락과 쿼터니언

- 짐벌락

짐벌락이란?

= x축(Pitch) y축(Yaw) z축(Roll) 의 세축이 회전을 하다가

특정 축이 특정각으로 회전을 했을 때 두 축이 겹쳐서 한축이 소실되는 현상을 말한다.

짐벌락 현상이 일어나는 이유!

1. 오일러 각을 이용하기 때문에

2. 오일러 각 회전을 순차적으로 하기 때문에

짐벌락 현상을 완벽하게 막을 방법?

- 단정적으로 말하자면 존재하지 않다.

즉, 우리는 짐벌락현상을 최대한 피하는 방법 밖에 없다.

짐벌락 현상을 최대한 피하는 방법

1. 오일러 각 회전의 순서를 바꾼다.

2. Axis라는 임의의 축회전을 이용한다.

3. 쿼터니언을 이용한다.

오일러 각 회전의 순서 바꾸기

- 잘 생각해보면 xyz 축회전에서 순서를 바꾸어 나타낼 수 있는 가지수는 총 6가지이다.

즉, xyz xzy yxz yzx zxy zyx 로 회전의 순서를 바꿀 수 있다.

여기서 잠깐! 순서를 정하는 방법을 알아보자.

1. 가장 자주 회전하게 될 축을 먼저 회전한다.

2. 가장 회전을 안하게 될 축을 2번째로 회전한다.

3. 남은 축을 회전한다.

이유!? 순서에 의한 짐벌락 현상은 두번쨰 회전하는 축이 90도(-90도)를 회전하게 되면

1번째 축과 3번째 축이 겹치면서 발생한다.

즉, 순서를 바꿔서 최대한 피하는 방법은 두번째 회전하는 축이 90도가 되지 않으면 된다.

다시 말해 두번째 회전하는 축이 회전을 자주하지 않으면 90도가 될 확률이 낮기에 위와같은 순서로 회전한다.

<영상 자료>

http://serviceapi.nmv.naver.com/flash/convertIframeTag.nhn?vid=3BC022F3654BF874381C994D9E29BBA102C3&outKey=V128a5c729f05a8b0b788bb9ead3d6b3a7a4ada8c814771624487bb9ead3d6b3a7a4a&width=720&height=438

Axis라는 임의의 축회전을 이용하는 방법

- 사실 아직 정보가 부족하다. 우선적으로 알고 있는 정보는

'D3DXMatrixRotationAxis' 라는 함수 이다.

이 함수는 인자로 결과행렬을 내 뱉고, 임의의 축이 될 벡터와 회전을 먹일 회전행렬을 인자로 원한다.

여기까지가 필자가 알고있는 Axis에 대한 정보이다.

하지만 이 임의의 축회전도 문제가 있다.

임의의 축을 놓고 회전할 때 보간의 처리( 선형보간, 구면보간 )의 문제로 회전 시에 뚝뚝 끊겨보이게 된다.

이 문제를 해결할 쿼터니언이 존재한다. ( 물론 쿼터니언도 완벽하게 짐벌락을 막을 수는 없다. )

쿼터니언은 비교적 어려운 수학적 학문이므로 다음 포스트로 옮기도록 하겠다.

다음 포스팅은 쿼터니언에 대해 정리하고

지금 이 포스팅에 이미지, 영상 추가 등

최종본으로 정리하도록 하겠습니다. ㅋ

*

수정 완료 ^^


아래 내용은 위 내용에 조금 추가하면

위의 이미지는 x 축을 회전 시키는 과정이고 아래 그림은 x 축을 90 또는 -90 도로 회전시켰을때 이고

이때 y축과 z 축이 같은 회전 선상에 있다는 것을 알 수 있다

이때 짐벌락이 발생한다

반응형
반응형

 


 

출처 : http://www.galexandria.com/

처음에

저는 쿼터니언이라는 용어가 마치 비밀스러운 어둠의 힘을 가지고 있는 암흑물체에 관한 양자론 용어처럼 느껴집니다. 여러분도 역시 이 어둠의 힘에 매료되었다면 이 글이 도움이 될 것입니다(그렇게 되기를 바랍니다). 이 글은 쿼터니언을 이용해서 회전을 하는 방법을 보여주어 쿼터니언을 좀더 쉽게 이해하는데 도움을 줄 것입니다. 만약 여러분이 글에서 잘못된 내용을 발견하시면 robin@cyberversion.com로 메일을 보내주세요. 또, 이 기사를 여러분의 사이트에 실으려고 하신다면 저에게 메일을 보내주세요. 저는 저의 글이 어디에 퍼져있는지 알고 싶답니다.

왜 쿼터니언을 사용할까?

이 질문에 대답하기 위해서 우선 방향을 나타내는 일반적인 방법에 대해 논의해 보도록 합시다.

오일러 표현

이것이 현재까지 알려진 방법중 방향을 나타내는 가장 간단한 방법입니다. 오일러 표현은 각각의 축마다 축주위의 회전량을 가지고 있습니다. 따라서, 다음과 같은 0도에서 360도(혹은 0~2π)의 범위에서 변하는 3개의 값을 가집니다.

x, y, z <-- 전역 좌표축 주위의 회전 각도

이 값은 각각 롤, 피치, 요(혹은 피치, 롤, 요, 등 등)를 표현합니다. 방향은 3개의 각도로부터 생성되는 3개의 회전 행렬을 지정한 순서대로 해서 구할수 있습니다.

Note: 회전은 전역 좌표계의 좌표축을 기준으로 회전합니다. 즉 최초의 회전이 그 후의 2번째 3번째의 회전축에 영향을 주지 않습니다. 이 때문에 짐벌락(gimbal lock) 문제가 발생하게 됩니다. 짐벌락에 대해서는 조금 후에 자세히 설명하겠습니다.

회전축과 각도(Axis Angle)에 의한 표현

이 방법은 짐벌락을 피할수 있으므로 오일러각 방법보다 좀더 낫습니다. 회전축과 각도에 의한 표현은 임의의 회전축을 나타내는 단위 벡터와 단위 벡터 주위의 회전을 나타내는(0~360) 값으로 구성됩니다.

x, y, z <-- 임의의 축을 나타내는 단위 벡터 angle <-- 바로 윗줄에서 정의한 축 주위로 회전 각도

왜 이 방법이 나쁠까요?

짐벌락

오일러 표현에 있어서 회전은 전역 좌표계에서 일어나기 때문에 한 축의 회전이 다른 축의 회전과 겹치는(override) 문제가 발생합니다. 따라서 회전을 할 수 있는 축 하나를 잃게 됩니다. 이것을 짐벌락이라고 합니다.

예를 들어, X축과 평행한 어떤 벡터를 Y축주위로 회전해서 그 벡터가 Z축과 평행하게 되었다고 하면 이 때, Z축주위로 아무리 회전시켜도, 벡터의 방향은 전혀 변하지 않게 됩니다.

나중에 여러분에게 짐벌락의 예와 쿼터니언을 사용해서 짐벌락을 해결하는 방법을 보여드리겠습니다.

보간 문제

회전축 표현이 짐벌락 문제로 부터 자유롭긴 하지만 두개의 회전을 보간하는 경우, 또 다른 문제가 발생합니다. 보간계산을 마친 회전들이 부드럽지 못하여 회전 애니메이션이 삑사리가 날 수도 있습니다. 오일러 표현도 마찬가지로 이 문제를 가지고 있습니다.

자. 쿼터니언으로 빠져 봅시다 !

시작하기에 앞서, 몇가지 가정을 세우겠습니다. 저는 수학적인 이해가 중요시되는 글에서 수학적인 내용들을 대충 생략해버리는 글들에 진절머리가 납니다. 이런 글들은 독자들을 혼란에 빠뜨리기 쉽상입니다.

좌표계 - 이 글은 OpenGL과 같은 오른손 좌표계를 사용합니다. 만약 여러분이 Direct3D 같은 왼손 좌표계를 사용하고 계시다면 행렬들을 전치(transpose)하셔야 합니다. 이미 Direct3D의 샘플들은 쿼터니언 라이브리러를 가지고 있다는 사실에 유념해주시기 바랍니다. 그럼에도 불구하고 저는 여러분이 그 라이브러리를 사용하시기 전에 그 내부가 어떻게 구성되는지를 한번 짚고 넘어갔으면 하는 바램입니다.

회전순서 - 오일러 표현에서 회전 순서는 X->Y->Z의 순입니다. 행렬 형태로 아래와 같이 표현합니다.

RotX * RotY * RotZ <-- 매우 중요

행렬 - 행렬은 OpenGL 처럼 열우선 방식으로 합니다.

예 [ 0 4 8 12 1 5 9 13 2 6 10 14 3 7 11 15 ]


벡터와 점 - 변환을 위해 벡터와 점은 4x1의 행렬로 표현합니다. 다음과 같은 모습입니다.

회전 행렬 * [ vx vy vz 1 ] <-- 4x1 벡터

저는 특히 Direct3D보다 OpenGL을 선호하지는 않습니다. 그저 제가 OpenGL을 먼저 배웠고, 쿼터니언도 OpenGL을 통해 익혔을 뿐입니다.

Note: 만약 X->Y->Z 순서가 아닌 다른 회전 순서를 지정하면 몇몇 쿼터니언의 함수들을 다시 구현해야 합니다. 특히 오일러 표현을 다루는 함수들이 그렇습니다.

쿼터니언이란 무엇인가?

복소수는 i라는 기호를 사용하여 정의하는 허수(가상의 수)입니다. i는 i * i = -1 라는 성질을 가지고 있습니다.

쿼터니언은 복소수의 확장입니다. i만 사용하는 것이 아니라 제근이 ―1 이 되는 3개의 허수를 가집니다. 이 3개의 수는 보통 i, j, k로 표기합니다. 다시 말해 이것은 다음과 같은 성질을 가집니다.

j * j = -1 k * k = -1

따라서 쿼터니언을 아래와 같이 표현할 수 있습니다.

q = w + xi + yj + zk

여기서 w는 실수, x, y, z는 복소수입니다.

흔히 사용하는 또 다른 표현은 아래처럼 벡터형태로 표현할수 있습니다.

q = [ w, v ]

여기서 v = (x, y, z)는 "벡터"라고 말하며 w는 "스칼라"입니다.

v를 벡터라고 부르지만 이것은 일반적인 3차원 벡터가 아닌 4 차원 공간상에 벡터를 표현한 것으로 직관적으로 시각화할 수 없습니다.

항등 쿼터니언

벡터와 다르게 2개의 항등 쿼터니언이 있습니다.

 항등 쿼터니언은 아래 처럼 표현합니다.

q = [1, (0, 0, 0)]

그래서 이  항등 쿼터니언과 해진 어떤 쿼터니언도 변하지 않습니다.

가산 항등 쿼터니언은 (저희는 사용하지 않습니다)은 아래처럼 표현합니다.

q = [0, (0, 0, 0)]

방향 표현으로 쿼터니언 사용하기

우선 저는 쿼터니언이 벡터가 아니라는 사실을 말씀드리고 싶습니다. 따라서 여기서 벡터 수학을 사용하지 말아주십시요.

이 부분은 매우 수학적인 내용을 다룰 것입니다. 참을성을 가지고 제 설명을 읽어주세요.

우선 쿼터니언의 크기를 정의합니다.

|| q || = Norm(q) = sqrt(w2 + x2 + y2 + z2)

단위 쿼터니언은 아래와 같은 속성을 가지고 있습니다.

w2 + x2 + y2 + z2 = 1

그 때문에 쿼터니언의 정규화는 아래와 같이 구합니다

q = q / || q || = q / sqrt(w2 + x2 + y2 + z2)

이 단위 쿼터니언은 특별합니다. 왜냐하면 단위 쿼터니언은 3D 공간에서 방향을 표현할 수 있기 때문입니다. 따라서 앞에서 논의된 두가지 방법 대신에 단위 쿼터니언을 통해 방향을 표현할 수 있습니다. 단위 쿼터니언으로 방향을 표현하려면 단위 쿼터니언을 다른 표현(예: 행렬)으로 변환하거나 반대로 변환하는 방법이 필요합니다. 이것에 대해서는 곧 설명드리겠습니다.

단위 쿼터니언 시각화 하기

단위 쿼터니언은 (x, y, z) 요소를 임의의 축, w요소를 회전 각도로 하는 4차원 공간상의 회전으로서 시각화할 수 있습니다. 모든 단위 쿼터니언들은 4D 공간에서 단위 길이를 가지는 구를 형성하게 됩니다. 다시한번 이게 무슨 소리지 하고 여러분은 직관적으로 이해가 안되실것입니다. 하지만 제가 정말 말하고 싶은 것은 쿼터니언의 스칼라 요소(w)의 부호를 반전시키는 것만으로 180도 회전한 쿼터니언을 얻을 수 있다는 것입니다.

Note: 단위 쿼터니언만을 방향표현에 사용할 수 있습니다. 이 뒤에 논할 모든 내용은 모두 단위 쿼터니언을 사용한다고 가정합니다.

쿼터니언으로부터의 변환

효과적으로 쿼터니언을 사용하려면 결국 쿼터니언을 다른 표현으로 변환해야 할 필요가 있을 것입니다. 키 눌림을 쿼터니언으로 해석할 수는 없지 않습니까? 할수 있으신 분 계신가요? 글쎄여. 아직까지는 없는 듯 하죠?

쿼터니언에서 행렬로의 변환

OpenGL와 DirectX는 행렬로 회전을 표현하기 때문에 쿼터니언->행렬 변환이 아마 가장 중요한 변환 함수일 것입니다. 왜냐하면 동차 행렬이 3D의 기본 표현이기 떄문입니다.

쿼터니언 회전과 동등한 회전 행렬은 다음과 같습니다.

 

행렬 = [ w2 + x2 - y2 - z2      2xy - 2wz       2xz + 2wy             0

            2xy + 2wz          w2 - x2 + y2 - z2   2yz - 2wx             0

            2xz - 2wy                2yz + 2wx    w2 - x2 - y2 + z2      0

                  0                            0                   0         w2 - x2 - y2 + z2]

 

 

w2 + x2 + y2 + z2 = 1이 되는 단위 쿼터니언의 속성을 사용하면 위 식을 다음과 같이 간단하게 만들 수 있습니다.

 

행렬 = [ 1 - 2y2 - 2z2          2xy - 2wz         2xz + 2wy            0

            2xy + 2wz            1 - 2x2 - 2z2       2yz - 2wx            0

            2xz - 2wy              2yz + 2wx        1 - 2x2 - 2y2         0

                  0                          0                     0                   1 ]

쿼터니언으로부터 회전축과 각도에 의한 표현으로 변환

한 쿼터니언을 삼차원 공간에서의 임의축 주위의 회전축과 각도에 의한 표현으로 변환하는 방법은 다음과 같습니다.

회전축이 (ax, ay, az)이고 각도가 theta (라디안)이면 각도는 angle= 2 * acos(w)가 됩니다. 그 때 ax= x / scale ay= y / scale az= z / scale 이 됩니다. scale은 scale = sqrt (x2 + y2 + z2)입니다..

제가 알고 있는 다른 방법은 scale = sin(acos(w))을 사용하는 것입니다. 저 스스로 수학적으로 동치관계를 증명하려고 하지는 않았지만 두 방법 다 결과는 같을 것이라 생각합니다.

어쨌든, scale이 0이라면 회전이 없다는 뜻입니다. 그리고 여러분이 특별한 조치를 취하지 않는다면 회전축이 무한대가 됩니다. 따라서 scale이 0인 경우에는 언제나 회전각이 0인 임의의 단위벡터를 그 축에 설정하시면 됩니다.

간단한 예

제가 설명하려고 하는 것들에 대해서 뭐가 뭔지 모르겠다 하시는 독자분들을 위해 이제부터 간단한 예를 보여드리겠습니다.

우선 카메라 방향을 오일러 각으로 표현한다고 해봅시다. 그러면 렌더링 루프에서 다음과 같은 식을 이용하여 카메라를 위치시킵니다.

RotateX * RotateY * RotateZ * Translate

이 때 각각의 요소는 4x4 행렬입니다.

이제 단위 쿼터니언을 사용해서 카메라의 방향을 표현하려면 먼저 쿼터니언을 행렬로 변환해야 합니다. 그러면

(쿼터니언으로부터 변환한 회전 행렬) Rotate * Translate

같은 것이 생기게 됩니다

OpenGL에 특화한 예는 다음과 같게 될것입니다.

오일러쿼터니언

glRotatef( angleX, 1, 0, 0)
glRotatef( angleY, 0, 1, 0)
glRotatef( angleZ, 0, 0, 1)
// 평행이동

// 오일러를 쿼터니언으로 변환
// 쿼터니언을 회전축과 각도로 변환
glRotate(theta, ax, ay, az)
// 평행이동

위의 표현은 모두 같습니다. 제가 말할려고 하는 것은 방향에 쿼터니언을 사용하는 것은 오일러나 회전축과 각도에 의한 표현과 완전히 같고, 앞서 언급한 변환 함수를 통해 상호교환이 가능하다라는 것입니다.

다만, 위의 쿼터니언에 의한 표현에는 오일러 표현법과 마찬가지로 짐벌락의 위험성이 있습니다.

역자주 – "왜 짐벌락 위험성이 있지"라는 답을 글내용상 알수가 없습니다.


물론, 아직은 회전을 쿼터니언으로 만드는 방법을 모르시겠지만 그것은 아래 부분에서 설명하겠습니다.

Note: Direct3D나 OpenGL를 사용하시는 독자분들은 API가 행렬 연결을 처리해주기 때문에 직접 행렬을 취급하는 일은 없겠지만, 이것에 대해서 알아둘 필요가 있습니다.

쿼터니언 

단위쿼터니언이 3D공간에서의 한 방향을 표현하기 때문에 2개의 단위 쿼터니언간의 은 2개의 단위 쿼터니언의 회전을 결합한 회전을 나타내는 단위 쿼터니언이 됩니다. 놀라운 일이지만, 사실입니다.

다음과 같은 2개의 쿼터니안이 있다고 가정해봅시다.

Q1=(w1, x1, y1, z1); Q2=(w2, x2, y2, z2);

이 2개의 단위 쿼터니언을 결합한 회전은 아래와 같이 구해집니다

Q1 * Q2 =( w1.w2 - v1.v2, w1.v2 + w2.v1 + v1*v2)

이 때 ,

v1 = (x1, y1, z1) v2 = (x2, y2, z2)

이 됩니다.

여기서 .와 *은 내적과 외적을 나타냅니다.

하지만 위 식을 아래와 같이 최적화할 수 있습니다.

w = w1w2 - x1x2 - y1y2 - z1z2 x = w1x2 + x1w2 + y1z2 - z1y2 y = w1y2 + y1w2 + z1x2 - x1z2 z = w1z2 + z1w2 + x1y2 - y1x2

물론, 여타 쿼터니언들과 마찬가지로 결과 단위 쿼터니언을 다른 회전 표현으로 변환하는 것도 가능합니다. 이런 점이 바로 쿼터니언의 진정한 미학입니다. 2개의 단위 쿼터니언은 구 상에 위치하기 때문에 4차원 공간에서 이들을 하는 방법은 짐벌락의 문제를 해결합니다.

여기서 하는 순서가 중요합니다. 쿼터니언의 은 교환칙이 성립되지 않습니다. 즉 이것은 아래의 식을의미합니다.

q1 * q2 ≠ q2 * q1

Note: 2개의 쿼터니언은 동일한 좌표계 축을 참조해야 합니다. 저는 서로 다른 좌표계에서 2개의 쿼터니언을 합성하는 실수를 범한 적이 있고, 이 때 그 결과 쿼터니언이 특정 각도에서만 실패하는 이유를 알아내기 위해 많은 시간을 고민했습니다.

쿼티니언으로의 변환

이제 다른 표현법을 쿼터니언으로 변환하는 방법을 배워봅시다. 저는 샘플 프로그램에 있는 모든 변환들을 사용하지는 않지만 역운동학 등의 보다 진보된 용도로 쿼터니언 방향을 사용하려고 할 때 이것들이 필요할 것입니다.

회전축과 각도(Angle Axis)로부터 쿼터니언으로 변환

3D공간에서의 임의의 회전축을 도는 회전은 아래처럼 쿼터니언으로 변환됩니다.

회전축이 (ax, ay, az) 이고 (반드시 단위 벡터여야 함) 회전 각도를 theta (라디안)이면 w = cos(theta/2) x = ax * sin(theta/2) y = ay * sin(theta/2) z = az * sin(theta/2)이 됩니다.

우선 회전축이 정규화되어 있어야 합니다. 만약 정규화된 회전축 벡터의 길이가 0이라면 회전이 없는 것을 의미하므로 쿼터니언은 단위(identity) 쿼터니언으로 설정되어야 합니다.

오일러로부터 쿼터니언으로 변환

오일러로부터 쿼터니언으로의 변환은 회전순서가 올바르지 않으면 안 되기 때문에 조금더 힘듭니다. 임의축으로부터 3개의 좌표축을 분해하면 오일러 각을 3개의 독립적인 쿼터니언으로 변환해서 이 3개의 쿼터니언을 하면 최종 쿼터니언을 얻을 수 있습니다.

따라서 오일러 각 (a, b, c)으로 세개의 독립적인 쿼터니언을 만들수 있으며

Qx = [ cos(a/2), (sin(a/2), 0, 0)] Qy = [ cos(b/2), (0, sin(b/2), 0)] Qz = [ cos(c/2), (0, 0, sin(c/2))]

최종 쿼터니언은 Qx * Qy * Qz로 구할수 있습니다.

역자주 –이것은 오일러 회전 순서가 x->y->z의 순서인 경우에만 해당됩니다. 다른 순서로 된다면 Qx * Qy * Qz이 다르게 표현됩니다

데모 - 짐벌락 피하기

드디어 "어떻게 쿼터니언이 짐벌락을 피할수 있지?"에 대해서 모두가 기다렸던 궁금증에 대답할 때가 왔습니다.

기본적인 아이디어는

  1. 회전을 표현하는 데 쿼터니언을 사용한다.
  2. 현재 방향에서 새로운 방향으로 변경하기 위해 하나의 임시 쿼터니언을 생성한다.
  3. 임시 쿼터니언과 원래의 쿼터니언을 한다. 이렇게 하면 양쪽 모두의 회전을 합성한 새로운 방향이 얻어진다.
  4. 이 결과 쿼터니언을 행렬로 변환해서 평소처럼 행렬 을 사용한다.

우선, 저는 샘플 코드에 대해서는 어떠한 책임도 지지 않겠습니다. 이 코드는 난잡스러고 제대로 구성되어 있지도 않습니다. 이것은 쿼터니언 테스트할 때 제 프로그램에서 사용했던 쿼터니언 코드를 간략히 줄여놓은 버전일 뿐입니다. 따라서 코드에 대해서 크게 신경을 쓰지 않았다는 점만 기억해 주셨으면 좋겠습니다(돈받고 파는 코드가 아니니까요 ^^)

저는 2개의 실행 가능한 샘플을 준비했습니다. 첫번째 프로그램인CameraEuler.exe (http://www.gamedev.net/reference/programming/features/qpowers/CameraEuler.zip)는 오일러 각을 사용해서 카메라를 구현한 예입니다.

여러분이 주의깊게 봐야 할 부분은 main.cpp의 Main_Lopp 함수입니다.

여러분이 while 문에서 눈여겨 봐야할 곳은 다음과 같습니다.

  1. X축, Y축, Z축 각각의 회전을, 3개의 각도로 보관 유지 부분
  2. 키를 누르면 관련된 회전량을 조정하는 부분
  3. while 문에서, 3 개의 오일러 각도를 회전 행렬로 변환해서 그것을 최종 변환 행렬에 하는 부분

위/아래 화살표 키는 X축의 회전, 왼쪽/오른쪽 화살표 키는 Y축회전, Insert/PageUp 키는 Z축회전을 담당합니다.

이 프로그램은, 짐벌락을 일으킵니다. 여러분이 짐벌락 현상을 보고 싶으면, 요를 90도로 취하고 X축이나 Z축회전을 시도해 보십시오. 그리고 무슨일이 일어나는지 살펴보세요.

지금부터는 쿼터니언으로 짐벌락 문제를 해결한 프로그램을 살펴봅시다. 이 프로그램은CameraQuat.exe (http://www.gamedev.net/reference/programming/features/qpowers/CameraQuat.zip)이며 앞의 프로그램을 조금 변경한 프로그램입니다.

여러분이 while문에서 눈여겨봐야하는 곳은 다음과 같습니다.

  1. 카메라 방향을 쿼터니언으로 표현한 부분
  2. 키 입력으로부터 3개의 각도를 얻는 부분. 이 3개의 각도는 on/off 스윗치이며, 누적되지 않는 다는 것에 주의하십시오. 저는 while문에 이것들을 리셋했습니다. 물론 이것이 최선의 방법은 아닙니다. 그냥 신속히 처리하기 위해서 그랬을 뿐입니다.
  3. 3개의 각도를 임시 쿼터니언으로 변환하는 부분
  4. 임시 쿼터니언과 카메라 쿼터니언을 해서 합성한 방향을 얻는 부분.  순서에 주의.
  5. 이렇게 해 얻은 카메라 회전을 최종 변환 행렬을 위해 회전축과 각도에 의한 표현으로 변환하는 부분.

키가 눌러졌을 때, 저는 키 입력에 대응하는 고유의 축에서의 작은 회전을 나타내는 임시 쿼터니언을 생성했습니다. 그리고 임시 쿼터니언과 카메라 쿼터니언을 했습니다. 이 4차원 공간에서의 회전을 합성한 것이 짐벌락을 피하게 해줍니다. 여러분이 직접 이것을 해보고 자신의 눈으로 확인해주세요.

카메라 쿼터니언은 최종 변환 행렬로 합성할 수 있도록 행렬이나 그에 상응하는 형태로 변환되야 합니다. 여러분이 쿼터니언을 사용할 때, 3차원 공간과 4차원 공간은 섞일 수가 없기 때문에 항상 이 작업을 해주셔야 합니다. OpenGL의 경우에 저는 그냥 쿼터니언으로부터 회전축을 변경하기만 했고 나머지는 API에게 위임했습니다.

제가 두번째 프로그램에서 오일러 각을 회전에 사용하지 않았지만 저는 여러분이 첫번째 프로그램에서의 오일러 회전에 대해서 볼 수 있게 하기 위해서 오일러 회전 부분을 남겨 두었습니다. 오일러 각은 하나 이상의 축으로 회전시키면 올바르게 되지 않을 것입니다. 왜냐하면 쿼터니언이 카메라 쿼터니언으로부터 오일러 각을 얻는 대신 키 입력을 통해서 계산하기 때문입니다. 두번째 프로그램은 프로그램을 시작했을 때 그냥 여러분이 요 값을 90도로 회전하려는 경우에 짐벌락이 더 이상 일어나지 않는다는 것을 보기 위해서 만든 참고자료일뿐입니다.

Note: 저는 여러분에게 저의 수학 라이브러리를 사용하라고 추천하고 싶지 않습니다. 여러분이 쿼터니언을 이해하고 나서 스스로 짜 보십시오. 참고로 저는 이 코드를 전부 버리고 다시 만들 예정입니다. 이 코드들은 저에게 있어서 너무나 지저분하고 난잡한 코드입니다.

제가 보여드리지 않은 것

여러분이 이미 눈치채셔겠지만 저는 쿼터니언을 오일러 각으로 변환하는 방법에 대해서는 설명하지 않았습니다. 그 이유는 아직까지도 완벽하게 동작하는 변환을 제가 알아내지 못했기 때문입니다. 제가 알고 있는 유일한 방법은 쿼터니언으로부터 행렬을 얻고, 그 행렬로부터 오일러 각을 추출하는 것입니다. 그러나, 오일러에서 행렬 변환은 다대일 관계(sin과 cos으로 인해)이기 때문에 저는 atan2를 사용해서 그 역을 구하는 방법을 알지 못합니다. 만약 정확하게 행렬로부터 오일러 각을 추출하는 방법을 알고 계시다면 저에게 알려주세요.

제가 보여드리지 않은 다른 내용은 행렬을 쿼터니언으로 변환하는 방법입니다. 여러분이 오일러 표현과 회전축과 각도에 의한 표현을 쿼터니언으로 변환할 때 행렬을 거치지 않고도 직접변환이 가능하므로 굳이 행렬을 쿼터니언으로 변환할 필요가 없기 때문입니다.

과제 - SLERP

여러분이 쿼터니언을 완전히 이해했다고 생각하신다면 다시 한번 생각해 보십시오. 아직도 쿼터니언에 대해서 더 배워야 할 게 남아 있습니다. 제가 전에 회전축과 각도(Axis Angle)에 의한 표현이 왜 나쁠까라고 말했던 것을 기억하시나요? '보간'이라는 단어가 갑자기 떠오르지 않나요?

저는 쿼터니언을 사용한 보간에 대해서 설명한 시간을 갖지 못했습니다. 이 글은 제가 예상한 것보다 시간이 오래 걸렸습니다. 여기서 SLERP(구면 선형 보간)에 대한 기본적인 아이디어를 드리겠습니다. 이것은 기본적으로 2개의 쿼터니언 방향 사이에 일련의 쿼터니언들을 생성합니다. 일련의 쿼터니언들은 처음과 마지막 쿼터니언사이에서 부드러운 모션(움직임)의 결과를 제공합니다. 오일러와 회전축 표현으로는 일관성있게 이러한 부드러운 움직임을 만들 수 없습니다.

마지막으로

저는 이 기사가 쿼터니언 이론 뒤에 숨겨진 알수 없는 미스테리들을 속시원하게 없애주었길 바랍니다. 다시한번 마지막으로 여러분에게 당부하고 싶은 말은 서로 다른 좌표계에서 2개의 쿼터니언을 하지 말아주십시오. 이렇게 하시면 여러분은 고통의 시간을 맛보시게 될것입니다.

그러면 새로 찾아낸 쿼터니언의 능력에 여러분이 기뻐하시길 바라면서 저는 이제 그만 여러분과 헤어질까 합니다. 몸조심하시구여. 그리구 다시 만나뵙기를 바라면서...

 

반응형
반응형

ttp://cs.sungshin.ac.kr/~hkim/LECTURE/CG/Shading/RayTracing.htm

 

 

 

 

 

Ray Tracing

 

 

 

 


특징


  
  물체를 화면에 표시하는 가장 기본적인 방법은 물체의 3차원 좌표를 시각변환과 원근투영 방법을 이용해서 2차원적 화면 좌표로 변환시키는 것이다. 또한 물체를 화면에 3차원적으로 표현하기 위한 방법 중의 하나인 와이어 프레임에 의한 간단한 표시법으로는 깊이감이 제대로 나타나지 않기 때문에 물체에 실제감을 더해주기 위해 은선과 은면제거 그리고 음영표현 방법을 사용해 보았다.

그러나 위와 같은 방법으로는, 아무리 실감 나는 표현을 한다고 해도 거울이나 투명한 물체 등을 표현하기는 불가능하다. 그것은 지금까지의 표시 방법이 눈과 물체와의 위치관계에 따라 좌표를 변환하는 것을 기본으로 하고 있지만, 거울면에서는 다른 위치에서 바라본 듯한 풍경이 나타나기 때문이다.

ray tracing 은 더욱 현실감 있는 표현이 가능방법으로서 광선추적이라고도 한다. 이것은 반사, 음영 만들기, 즉 유리 물체 등에 있어서의 빛의 굴절을 정확히 모사하고, 보다 현실에 가까운 입체표현이 가능한 방법으로 가장 유효한 랜더링 방법이다 
   Ray Tracing은 광선의 경로를 하나하나 추적하여 눈에 들어오는 빛을 찾아내는 방법인데, 이 방법을 이용하면 굴절과 반사의 효과를 나타내는 데 있어 그리 어렵지 않다. 평범한 다면체들을 그려내기 위해 Ray Tracing 방법으로 광선을 일일이 추적하는 것은 비효율적이지만, 거울이나 투명체를 표현하는 데 있어서는 Ray Tracing이 가장 알맞은 방법이다.

Ray Tracing의 또다른 장점은 은면제거 알고리즘이 따로 필요하지 않다는 것이다. 그 이유는 가려진 물체가 발산하는 빛은 우리의 눈에 직접 들어오지 않고 다른 물체에 닿아버리므로 결국 이 빛은 화면에 표시되지 않기 때문이다. 그러나 광선을 하나씩 추적한다는 말에서 느낄 수 있듯이, 비록 광선추적 알고리즘 자체는 그리 복잡하지 않다 하더라도 전체적인 계산량이 많아진다는 단점이 있다.

 
광선추적법을 이용한 표현


 

 

1. 투명물체와 경면반사의 표현이 가능  
2. 은면소거의 처리가 불필요  
3. 초병렬처리가 가능  

 

 


  
 


광선추적의 기초


 

Ray Tracing이란 관찰자의 눈에 들어오는 광선을 찾아 그 광선의 색을 화면에 표시해주는 방법으로서, 여러 방향에서 관찰자의 눈으로 들어오는 광선들의 색을 정확히 찾기만 한다면 영상을 만드는 일은 아주 간단해진다.

광선을 추적하는 방법에는 두 가지가 있는데, 하나는 광원이 내보내는 빛의 방향을 세분하여 추적하는 정방향 광선추적법이고, 다른 하나는 관찰자의 눈에서 광원방향으로 시선을 추적하는 역방향 광선추적법이다.

(1) 정방향 광선추적법(Forward Ray Tracing)

정방향 광선추적법은 역방향 광선추적법에 비해 자연현상을 좀더 충실하게 시뮬레이션한다는 장점이 있기는 하지만, 광원이 내보내는 여러 방향의 광선을 모두 추적해야 하는 비능률적인 면이 있다. 즉, 우리가 수많은 방향으로 세분화시킨 광선들을 모두 추적한다 해도, 그것들 중 대부분은 우리의 눈에 들어오지 않을 뿐만 아니라 그러한 광선은 영상을 만들어내는 데 전혀 도움이 되지 않기 때문이다. 그러므로 충분한 개수의 광선이 눈(화면)에 들어오도록 만들려면 광원에서 출발한 광선들을 거의 무한하게 세분화시켜야 한다는 것을 알 수 있다. 그러나 광원을 떠나는 빛을 셀 수는 없는 일이므로, 사실 이러한 방법으로 자연현상을 흉내내는 일은 거의 불가능하다.

(2) 역방향 광선추적법(Backward Ray Tracing)

관찰자의 시선방향을 따라가서 빛을 내보낸 물체를 찾아내는 방법이다. 시선이 물체에 닿았다는 것은 그 방향에서 물체의 빛이 눈으로 들어오는 것을 의미하므로, 시선방향으로 빛을 역추적하면 눈에 들어올 광선만을 추적할 수 있게 된다. 그러므로 광원에서 나오는 무한히 많은 빛들 중에서 눈에 들어올 빛을 찾아내는 정방향 광선추적법보다 시선방향으로 빛을 역추적하는 역방향 광선추적법이 훨씬 효율적임을 알 수 있다.

역방향 광선추적법이란 이러한 역추적 방법을 뜻하는 것으로서, 시선의 경로를 따라가다가 빛을 분산시키는 물체에 도달하면 Shading 모델로 광선의 색과 밝기를 결정하는 방법이다. 일반적으로 Ray Tracing이라 하면 광원에서 광선을 추적하는 정방향 광선추적법이 아닌 눈에서 광원으로의 시선추적 방법인 역방향 광선추적법을 의미한다.



Ray Tracing에서는 시선을 추적하므로, 모든 계산이 물체를 나타내는 3차원의 실좌표계(World Coordinate)상에서 이루어진다.

눈에서 출발하는 시선을 설정하는 원리는 눈과 물체사이에 화면을 놓고 화소와 시선을 대응시키는 것이다. 눈에서 출발한 시선을 따라가다가 거울을 만나게 되면 시선을 반사시켜 방향을 바꾸어준 뒤, 시선과 만나는 다른 물체를 찾는 일을 되풀이한다. 그리고 헝겊과 같이 빛을 분산시키는 물체에 시선이 닿게 되면 더 이상 시선을 추적하기 어려우므로 헝겊의 색을 화소에 칠해주는데, 이 경우 단순히 한가지 색채만을 쓰는 것이 아니라 광원과 물체 표면과의 각도 관계를 이용하여 색에 밝기를 더해준다.

Ray Tracing에서는 시선을 직선방정식으로 나타내고, 직선과 물체의 교점을 계산하는 방법을 사용하며, 여러 물체와의 교점 중에서 가장 가까운 교점을 시선이 도달한 곳으로 생각한다.

 

 

 


광선추적 알고리즘


 

매끄러운 평면에 광선이 조사되면, 일부는 반사하고 일부는 내부를 향해 나아간다. 반사광선은 입사각  와 같은 각도로 반사하지만, 내부로 향하는 광선의 방향은 물체를 구성하는 물질의 굴절률에 따라 다르다.  표면에서 분리된 2개의 빛은 다시 다른 표면에 조사되어 분리된다. 아래 그림  (a)와  같이 다수의 반사, 굴절을 반복하여 시점으로 향한 빛이 실제로 관찰  되어진다. 즉, 시점에서 관측되어진 명도 I는 그림(b)의 나무로 표현되는 것과 같이,  반사광, S1과 물체 내부로부터의 투과광T1의 합으로 주어진다. 이 나무구조는  무한히 계속된다. 

종래의 음영모델을 이용하는 경우, 광원으로부터 출발해서 반사, 분리의 반복을 계산하면 시접까지 도달한 빛은 극히 적고, 다른 많은 연산처리가 그래픽 표현에는 불필요하게 되고 만다. 따라서 레이트레이싱에서는 역으로 시점방향에서 출발해서 최종적으로 얻고 싶은 2차원 디스플레이상의 화살의 각 화소점만의 컬러정보를 얻는 수법을 이용하고 있다.  
그것은 옆 그림에서 나타나듯이, 시점 I로부터 화상평면의 각 화소점 (m,n)을 향해서 단위광원을 방사하여 그 광선과 물체의 교점을 구하는 작업과 교점에 잇어서 물체의 컬러정보를 구하는 작어븡로 구성된다. 그때, 각 화소점과 핀홀을 연결한 광선이 대상물체와 한번도 교차하지 않으면 배경색(예를 들어 흑)이 된다. 혹시 물체와 교차하면 대상물체가 불투명한 경우는 그림자 모델에 의해 그 점의 밝기를 계산한다. 

이상을 정리하면 다음과 같은 알고리즘이 되고 모든 것이 투명 물체인 경우의 기본적인 레이트레이싱법이 된다.  
 

1. m,n의 초기값을 설정한다.  
2. 시점I로부터 화소(m,n)에 광선을 방사하고, 모든 물체와의 교점을  구한다.  
3. 교점이 존재하면 화상평면에 가장 가까운 교점을 구한다.  
   교점이 존재하지 않으면 5번으로 간다.  
4. 3점의 물체의 그림자 만들기를 행하고, 색을 결정해서 화소(m,n) 에 부여한다.  
5. 화소(m,n)를 배경색으로 한다.  
6. 이상의 처리를 모든 화소에 대해 행한다. 

 

유리구 등과 같이 투명한 물체의 경우는 스넬의 법칙에 나타내듯이, 반사광 그 속으로 들어가는 투과광을 생각해서 임사되어진 단위광량 1을 적당한 비율로 반사광과 투과광에 분배한다. 그리고, 각각의 빛이 투명한 물체에 닿은 경우, 각각이 가진 광량에 비례해서 각 불투명 물체의 색을 혼합하고, 화소점의 컬러 정보로 한다. 혹시 두 개로 나뉘어진 빛이 다시 투명물체에 닿았을 때는 똑 같이 반복반사와 투과를 계산한다. 이렇게 해서 가지고 있는 광량이 어떤 명도 이하가 되든가, 반사의 횟수가 어떤 제한을 넘으면 계산을 그만두게 하면 된다. 이와 같은 계산을 화상평면상의 모든 화소점에 대해서 행하면 레이트레이싱 화상이 구해진다. 아래의 왼쪽그림은 렌즈 등의 투명한 유리구가 있는 경우의 레이트레이싱 화상 예이고, 아래의 오른쪽 그림은 경면반사가 있는 경우 화상의 예이다. 

 

심화 학습

Recursive Ray Tracing

 

  
 
 


광선 교점의 계산


  
레이트레이싱에서는 교점 계산에 많은 시간이 소요된다. 따라서, 물체와의 교점 계산법에 대해서 살펴보자.
 

시점의 위치를 P0(x0,y0,z0)으로 하고, 디스플레이상의 점을 Pmn(x1, y1, z1) 으로 하면, P0에서 Pmn에 도달하는 광선은 t를 이용하면 아래의 식으로 주어진다. 
 
여기서 
 
라고 놓으면 

 

가 된다. 이때 t를 음의 값으로 하면 광선은 시점으로부터 멀어지는 방향이 되고, t를 1보다 크게 하면, Pmn으로부터 물체가 존재하는 공간으로 들어오는 것이 된다. 이렇게 해서 모든 물체와의 교차판정을 행하고 가장 시점에 가까운 교점과 그 물체를 구한다.  
 
광선과 구의 교점

대상물체가 다음 식으로 나타내어지는 구체라고 하면 

 
식 2을 식 3에 대입하면 

가 된다. 이식은 t의 2차방정식이다. 따라서 이 식이 실근을 가지지 않으면 구와 광선과의 교점은 없는 것이 되고, 하나의 실근을 가지면 접하고, 두 개의 실근을 가질 때에는 작은 쪽의 t가 최초의 교점의 위 값이 된다.  
  

 
광선과 면의 교점

대상 물체가 폴리곤으로 구성되어 있는 경우는 우선 처음에 광선과 폴리곤을 포함하는 평면과의 교점을 구하고, 그 교점이 폴리곤의 내부에 존재하는지의 여부를 판정하게 된다.  
폴리곤을 포함하는 평면의 방정식을 다음 식으로 한다. 

여기에 식2를 대입한다. 

 

이 식으로부터 다음이 구해진다.  
  

혹시 t = 0 이 되면 평면과 광선은 평행이 되어 교차하지 않는 것이 된다. 교점이 폴리곤 내부에 있는지 여부의 가장 간단한 판정방법은 아래 그림에 나타나듯이 , 폴리곤과 교점 P를 xz평면상에 투영하는 것이다. 투영한 점 P 가 투영되어진 폴리곤 내부에 존재하면 교점이 존재하는 것이 된다.  
  

 


고속화 기술


 

레이트레이싱은 효과적인 렌더링법이지만 디스플레이 평면의 해상도가 높을수록 광선의 수가 증가하고 처리시간이 걸린다. 또 대상물체가 증가할수록 광선과 물체와의 교차를 판정하는 시간이 걸리고, 처리 시간이 방대해지는 결점이 있다.  그 때문에 다수의 고속화 알고리즘이 개발되어 있다.  고속화의 방식에는 하드웨어 방식과 소프트웨어 방식이 있다.  
하드웨어 방식에 대해서는, 레이트레이싱에서는 각 화소점의 계산이 독립적이어서 다른 영향을 받지 않는다는 사실로부터 병렬처리가 가능하고,기본적으로 프로세서의 수를 증가시키면 그 만큼 고속화가 실현된다.  그 때문에 많은 병렬처리 시스템이 제안되어 있다. 

(1) Supersampling

Ray Tracing에 의한 영상을 얻기 위한 기본적인 표시법은 화소 하나에 시선 하나씩을 대응시키는 방법이다. 이 방법의 결점은 물체 사이의 경계부분에서 색의 차이가 심하면 경계의 형태가 마치 계단과 같은 모습으로 나타난다는 것이다.

Supersampling은 이러한 한계를 개선하기 위해 고안된 방법으로서, 화소를 더 세분하고 하나의 화소에 여러개의 시선을 설정하여 추적하는 방법이다. Supersampling에서는 세분한 시선들의 밝기를 평균하여 화소의 색을 얻는데, 이는 높은 해상도의 가상적인 영상을 화면의 해상도로 낮추어 표시하는 것과 같다. 물론 이 방법으로 모든 결점을 완전히 해결할 수 있는 것은 아니지만, 색의 변화가 심한 부분에 중간색이 나타나므로 보다 현실감이 높은 영상이 얻어진다.

Supersampling을 한다고 해도 광선의 방향을 일정한 간격으로 세분하는 방법을 사용하면 경우에 따라서 아주 이상한 영상을 만들어내는 수가 있는데, 일 예로 광선의 세분간격과 비슷한 간격의 무늬를 가지는 물체는 그 무늬가 제대로 표현되지 않는다. 광선을 아무리 세분한다고 해도 일정한 간격으로 세분한 이상은, 이러한 현상을 완전히 막을 수는 없다.

그러나 현실감을 높이는 대신 그만큼 계산량이 늘어나게 되는데, 예를 들어 화소를 2×2의 격자로 세분한다고 하면 대략 계산량이 4배로 늘어나게 된다.

(2) Distributed Ray tracing

이러한 현상을 막기 위해 고안된 것이 distributed ray tracing(광선의 분산 추적)이다. 이것은 시선의 방향에 난수를 더하여 "확률적 분포"를 가해주는 방법으로서, 시선을 설정할 때나 반사와 굴절을 계산할 때 방향을 불규칙하게 흐트러뜨리면 일정한 시선간격에 의한 결점이 나타나지 않을 뿐만 아니라 빛이 번지는 효과도 얻을 수 있다는 원리를 이용한 것이다. 그러므로 그림자의 계산에 이 방법을 도입하면 그림자의 경계면이 흐려지는 효과를 얻을 수 있다.

Distributed Ray tracing 방법을 사용하였을 경우, 영상 전체를 보아서는 빛이 번지는 효과가 난다고는 할 수 있겠지만, 실제에 있어서는 난수에 의해 영상의 세부에 거칠 거칠한 무늬가 나타나게 된다. 그러므로 부드럽게 빛이 번지는 효과를 얻으려면 Supersampling 방법과 병행하여 사용해야 한다.

(3) 공간분할법(Space Subdivision)

Ray Tracing의 계산시간이 많이 걸린다는 단점을 보완하기 위한 방법으로 공간분할법은 물체를 정의한 실 좌표계 공간을 여러 영역으로 세분하고 물체를 영역별로 분류하여, 시선이 지나가는 영역내에 있는 물체들로만 교점테스트를 하므로 불필요한 계산을 줄일 수 있다.

즉, 각 영역에 물체가 하나씩만 있도록 세분한 다음 시선이 지나가는 영역을 효율적으로 찾기만 한다면 교점계산의 부담이 많이 줄어든다.

왼쪽그림과 같이 대상물체가 존재하는 공간을 8분할하고, 그 부분영역을 다시 8분할해 나가서 적당한 크기의 입방체가 될 때까지 부분분할해 간다. 이때, 각 부분영역과 대상물체와 관계는 아래 그림에 나타나듯이 무관계, 일부분관통,내부에 존재의 3가지가 있다. 그리고 광선이 직진하면 순차통과하는 부분영역이 구해지고, 각 부분영역마다 대상물체와의 관계가 구해져 있기 때문에, 그림 b,c,의 경우에 대해서만 교점계산을 행하면 된다. 처음에 대략적인 부분영역을 이용해서 판정하고, 혹시 b,c의 경우가 되면 재차 8분할하는 것보다 효율적으로 교점이 구하여 지게 된다. 부분영역의 계산기 내부에서의 기억방식으로 8분할 트리표현(octree structure)이 이용되어지고 있다. 

(4) 은면제거 알고리즘의 이용

반사체가 많은 그림이라도 시선의 방향이 변하는 평균횟수는 얼마되지 않는다. 또한 반사체나 투명체가 전체 그림에서 차지하는 면적도 얼마 되지 않는다. 그러므로 반사체나 투명체를 제외한 부분을 기존의 은면제거 알고리즘으로 그려낸 후 남은 부분에 대해서만 Ray Tracing을 행하면 계산량을 상당히 줄일 수 있을 것이다.


(5) 볼록포의 이용

대상물체가 복잡한 형상을 하고 있으면, 광선과 대상물체의 교차 여부의 판정에 시간이 걸리며 전체처리 시간의 95%이상이 소요된다고 말하여 진다. 따라서 대상이 되는 입체를 내부에 포함하는 간단한 볼록입체를 이용하고, 이 입체를 새로이 볼록포라고 부르기도 한다. 볼록포와 광선의 교차를 우선 구하여 교차하지 않으면, 원래의 입체는 교차하지 않음을 확실히 알 수 있다.혹시 볼록포와 광선이 교차하고 있으면 실제로 대상물과 광선이 교차하는지의 여부를 종래대로 광선추적의 처리로 구한다.  
볼록포는 교차계산이 용이한 입방체와 구가 이용되어진다. 그러나, 최적형상의 볼록포의 결정은 어려우므로, 현재에도 여러 가지 검토가 행하여 지고 있다. 보통은 아래 그림에 나타나듯이, 볼록포를 광선에 수직한 면에 투영했을 때,볼록포내의 물체가 포함되지 않은 영영(void area)이 적은 쪽이 바람직하다. 

반응형

'수학 (Mathematics) > 3D수학' 카테고리의 다른 글

짐벌락 피하는 방법  (0) 2012.11.02
쿼터니언  (0) 2012.11.02
크래머 공식  (0) 2012.11.02
행렬식  (0) 2012.11.02
1차 독립  (0) 2012.11.02
반응형

[여인수로 행렬식 계산하기]

 

A= ( 3 X 3 )  행렬이 있다고 가정

 

행 기준

3

∑ A_kj = (-1)^(k+j) a_kj * M_kj

j=1

 

열 기준

3

∑ A_jk = (-1)^(j+k) a_jk * M_jk

j=1

 

 

k    = 사용자 지정 행 번호  , if k=1 일때 1 행에 대한 연산 수행

a_kj = A 행렬에 해당하는 k,j 번째 원소

M_ij = 해당 k 행  ,j 열 을 제외하면 (2X2) 행렬이 나오고 이것에 대한 행렬식을 계산한다

 

총 3회의 연산으로 행렬식 연산을 마친다

 

 

 

 

 

 




http://carstart.tistory.com/160


[선형대수학] 5. 크래머 공식 (Cramer's Rule)


2010. 12. 27 (月)





연립일차방정식은 중학교 인지 고등학교인지는 모르겠지만 아무튼 수학시간에 배웠다.

이런 연립일차방정식을 중고등학교때는 간단하게 손으로 풀수 있는 수식이다.

하지만 대학 이상 수준에서는 간단하게 손으로 풀수 있는 정도 일가? 물론 아니다 ^^





이 연립방정식을 우리가 중고등학교 때 필수로 배우라 한 이유가 무엇일가 ?

실질적으로 우리 생활 회로해석이라든지 3D, 영상처리, 천문분야 등등 다양한 분야에서는 
이 연립 방정식을 계산할 때 많이 사용한다. 물론 간단한 연립방정식이 아니다. 
그래서 이를 미리 연습해본 것이다.
이제는 대학와서 복잡한 연립방정식을 풀게 된다. 
우리는 지금까지 이를 풀기위해 행렬을 배웠고 행렬식을 푸는 방법에 대해서 배웠다. 






그럼 이런 복잡한 연립방정식을 어떻게 풀죠?

보통 연립방정식 또는 행렬식을 푸는데는 

대치법 (substitution)
가우스 소거법 (Gaussian elimination)
크레머 공식(Cramer's Rule))

다양한 방법이 있다.





그럼 크래머 공식은 무엇인가요 ?

다음과 같은 n까지 있는 연립방정식을 풀려고 한다.



우리는 이를 풀기 쉽게 계산하기 위해 행렬로 표현할 수가 있다.

    B       =                 A                       X


여기에서 위의 행렬을 다음과 간단하게 나타낼 수 있다.
B = AX

여기서 


A 는 n * n 정방행렬 
X 와 B 는 n * 1 인 열벡터 임을 알 수있다.



내용 추가 :
A : 계수행렬
A*x = b   인데

이때 |A| != 0  A의 행렬식이 0 이 아니면 가역(역행렬을 갖으면) 다음과 같은 연산이 가능하다
A(A^-1)*x = (A^-1)b
I*x = (A^-1)b
x = (A^-1)b

그런데 A^-1 = (  1/|A| adj_A )  임으로
x = (  1/|A| adj_A )b

이를 정리하면 x에 대해 구할 수 있다, 자세한 증명은 패스

간단요령은 x 를 행렬 A 의 각 열에 넣는데 이때 
각 열에 넣을때 b 가 들어가는 열은 adj_A 연산에서 b 부분은 i,j 행열을 제외한 행렬식 연산후 b 의 값을 곱해주는
용도로만 사용되기 때문에 b 가 A 행렬 안에 들어갈 수 있는 형태가 된다





각각의 해는 다음과 같이 표현이 가능합니다. 


     는 행렬 A의 행렬식값 나타냅니다.
  n 는 행렬 A에서 제n열의 값을 B로 바꾼 행렬식값을 나타냅니다.

이를 크래머 공식이라고 합니다.

여기서 수학적인 증명은 생략하도록 하겠습니다. ^^;;





크래머 공식을 하기위한 조건이 있나요 ?

B = AX

여기서 B 가 영행렬 이면 이를 동차라 하고 그렇치 않으면 비동차라 합니다.
그리고 A 가 정칙행렬(역행렬이존재) 하는 경우에는 비동차연립일차방정식으로 AX =B는 유일한 해를 가지게 됩니다.
이 조건을 만족하면 크래머 공식이 성립합니다.





말로는 설명이 어려워요 한가지 예를 들어 설명해 주세요!


간단하게 3개의 연립방정식을 풀어보겠습니다.



이를 행렬식으로 표현합니다.
   B         =                A                       X

   
B 행렬은 0 행렬이 아닙니다.
A 행렬은 역행식 값이 0이 아니기 때문에 정칙행렬 입니다. 


두 조건을 만족하니 크래머 공식을 이용하여 각각의 해를 구합니다.

 
 



결과 입니다 ^^

반응형

'수학 (Mathematics) > 3D수학' 카테고리의 다른 글

쿼터니언  (0) 2012.11.02
광선추적 (Ray Tracing)  (0) 2012.11.02
행렬식  (0) 2012.11.02
1차 독립  (0) 2012.11.02
3차 곡선(Cubic polynomial curves )  (0) 2012.11.02
반응형



http://blog.naver.com/rlawldyd0806/50036277924




행렬식



-행과 열이 같은 정방 행렬에서만 구할 수 있다

정방 행렬 A에 대한 행렬식 표현

detA = det(A) = |A|

 

행렬식을 계산하기 위해 필요한 두 가지 개념

1. 소행렬식(minor)이라는 것으로, (i, j)소행렬식 Mij 는 nXn정방 행렬A에서i번째행과

    j번째 열을 제외한 (n-1)X(n-1) 정방 행렬의 행렬식을 의미

2. 여인자(cofactor)라는 것으로 ij = (-1)i+jij로 표현

 

소행렬식 및 여인자 예)

 가 주어졌을 때, 여인자 12 와 31은?

여인자 식에 대입하면 12 = (-1)1+231와 31 = (-1)3+131된다.

 

소행렬식  12  

소행렬식 31  

 여인자  여인자

 

D3DX함수

여인자를 구하는 함수는 지원하지 않는것 같다.

 

사용자함수

//소행렬식을 구하여 여인자 구한다.

D3DXMATRIX *MYMatrixCofactor(D3DXMATRIX *pOut, D3DXMATRIX *pMat)
{
 pOut->_11 = (pMat->_22 * pMat->_33 - pMat->_23 * pMat->_32);
 pOut->_12 = -(pMat->_21 * pMat->_33 - pMat->_23 * pMat->_31);
 pOut->_13 = (pMat->_21 * pMat->_32 - pMat->_22 * pMat->_31);

 pOut->_21 = -(pMat->_12 * pMat->_33 - pMat->_13 * pMat->_32);
 pOut->_22 = (pMat->_11 * pMat->_33 - pMat->_13 * pMat->_31);
 pOut->_23 = -(pMat->_11 * pMat->_32 - pMat->_12 * pMat->_31);

 pOut->_31 = (pMat->_12 * pMat->_23 - pMat->_13 * pMat->_22);
 pOut->_32 = -(pMat->_11 * pMat->_23 - pMat->_13 * pMat->_21);
 pOut->_33 = (pMat->_11 * pMat->_22 - pMat->_12 * pMat->_21);

 return pOut;
}

 

여인자를 이용한 행렬식 표현

동일한 열 성분(a1j, a2j•••, anj)에 대해서 표현

 

 

동일한 행 성분(aj1, aj2•••, ajn)에 대해서 표현

 

 

1X1정방 행렬  A=[a]의 행렬식 |A|=a

 

2X2정방 행렬 의 행렬식 계산

 

2X2정방 행렬식은 대각선 성분의 곱(a11a22)을 비대각선 성분의 곱(a12a21)으로 뺀 모양이다

 

3X3정방 행렬의 행렬식

       

    

 

 Direct3D 함수

FLOAT D3DXMatrixDeterminant(CONST D3DXMATRIX *pM);

 

사용자 함수

//행렬의 행렬식을 구한다.

float MYMatrixDeterminant(D3DXMATRIX *pM)
{
 return (pM->_11*pM->_22*pM->_33) + (pM->_12*pM->_23*pM->_31) + (pM->_13*pM->_21*pM->_32)
      - (pM->_11*pM->_23*pM->_32) - (pM->_12*pM->_21*pM->_33) - (pM->_13*pM->_22*pM->_31);
}

반응형

'수학 (Mathematics) > 3D수학' 카테고리의 다른 글

광선추적 (Ray Tracing)  (0) 2012.11.02
크래머 공식  (0) 2012.11.02
1차 독립  (0) 2012.11.02
3차 곡선(Cubic polynomial curves )  (0) 2012.11.02
곡선, SVG 곡선 사이트 링크들  (0) 2012.11.02
반응형

V1 + V2  을

상수 C1, C2 를 각각에 곱해 + 로 연결한 것을

C1V1 + C2V2 => 선형 결합 이라고 하며

이때 


C1V1 + C2V2 = 0 이 되는 것이

C1,C2 가

C1=C2=0 일때만 C1V1 + C2V2 = 0 이 성립되는 것을

1차 독립이라고 한다


x + 2x = 0 은 1차 독립이 아니다

ax + 2x => a =-2 면 0 이 됨으로

e^x * e^2x 은

a1 e^x * a2 e^2x => a1=a2=0 일 때만 결과가 0 이 되면 1차 독립

이게 a1=a2=0 가 0 일때만 결과가 0 이 되는지는 검증을 해봐야 되는데 아무튼... 

상수가 0 인가 그리고 그때뿐인가가 중요한 포인트

반응형
반응형

http://blog.naver.com/astone94/90101243937



에르미트(Hermite)[1]곡선과 베지에(Bezier)[2]곡선은3차 곡선의 두 예입니다이들은 네가지 매개변수에 의하여 정의됩니다에르미트 곡선은 두 끝점과 이 점에서의 탄젠트 벡터(tangent vectors)로 정의됩니다베지에 곡선은4개의 점으로 정의됩니다이 둘은 수학적으로 다르지만 그 둘의 특징과 한계는 매우 유사합니다



[1]더 많은 정보를 위해서는 http://en.wikipedia.org/wiki/Cubic_Hermite_spline를 참조하세요.

[2]더 많은 정보를 위해서는 http://en.wikipedia.org/wiki/B%C3%A9zier_curve를 참조하세요.

대부분의 경우곡선은 여러가지 요소들에 의하여 만들어집니다이 요소들은 구간적3차 곡선(piecewise Bezier curve)을 만들기 위해서 필요합니다아래는 구간적 베지에 곡선의 예로  10개의 점(storage point)을 이용하여3개의 구간을 가진 곡선(a three-segment curve)를 나타낸 것입니다.이 곡선들이 아래 그림과 같이 연결(join)되어도 이것이 부드럽게 연결되지는 않습니다.

에르미트 곡선이 베지어 곡선과 같은4개의 매개변수를 사용한다고 하여도탄젠트라는 추가적인 방향 정보를 가지고 있습니다에르미트 곡선들을 연결할 때 이러한 방향정보를 이용하여 각 끝점의 방향을 일치키시면 적은 용량으로도 더욱 부드러운 곡선을 표현할 수 있습니다.

[1]더 많은 정보를 위해서는 http://en.wikipedia.org/wiki/B%C3%A9zier_curve를 참조하세요.

더욱 부드럽고 연속적인 곡선을 표현하기 위해 찾아진 방식 중 가장 강력한 것으로, Non Uniform Rational B-Spline[1](NURBS)가 있습니다곡선 조각들은 적은 정보량으로 더욱 부드러운 곡선을 포현하기 위해 더 많은 컨트롤 포인트를 공유하게 됩니다.


NURBS 곡선과 곡면(surface)들은Rhinoceros에서 기하체를 표현하기 위해 사용됩니다. NURBS곡선들의 특징과 요소들은 이 챕터의 뒷 부분을 통해 더욱 자세하게 다뤄질 것입니다.

3차 곡선의 매개변수 방정식은 다음과 같습니다일반적인 모델링 작업에서 이러한 공식을 사용할 가능성은 거의 없지만이것을 참고적으로 이해하는 것은 도움이 될 것입니다.

3차 곡선의 매개변수 방정식은 다음과 같습니다.

이를 아래와 같이 바꿔 쓸 수 있습니다.

x(t) = ax3+ bx2+ cx+ dx

y(t) = ay + by2+ cy+ dy

z(t) = az3+ bz2+ cz+ dz

Q(t방정식은 아래와 같이 써질 수 있습니다.

Q(t) = CT

T가 다음과 같고.

C가 계수 행렬(the matrix of coefficients)이라고 한다면

 

[1]더 많은 정보를 위해서는 http://en.wikipedia.org/wiki/Non-uniform_rational_B-spline를 참조하세요.

행렬의 곱을 이용한 곡선 방정식은 다음과 같습니다.

 

반응형
반응형

ttp://en.wikipedia.org/wiki/B%C3%A9zier_curve#Cubic_B.C3.A9zier_curves





 
 


반응형
반응형

브레슨햄 동영상 강의

http://forum.falinux.com/zbxe/?document_srl=406146









http://blog.naver.com/nowcome/130019875263


#include <iostream>
using namespace std;

#define max( x, y) (((x) > (y)) ? (x) : (y)) // 큰수 찾는거 당연히 아시겠줘? 

#define abs( x ) (((x) > 0) ? (x) : -(x)) // 절대값. 

#define sign( x ) ((x) > 0 ? 1 : ((x) == 0 ? 0: (-1))) // 양수:1, 0, 음:-1 

#define WIDTH   30
#define HEIGHT  25


char array[HEIGHT][WIDTH]={{'\0',},};

void show(){

 for (int j=0;j<HEIGHT;++j)
 {
  for (int i=0;i<WIDTH;++i)
  {
   cout<<array[j][i]<<" ";
  }
  cout<<"\n";
 }
 

}

void initial(){
 for (int j=0;j<HEIGHT;++j)
 {
  for (int i=0;i<WIDTH;++i)
  {
   array[j][i]=' ';
  }
 }
}

void drawPoint(int x,int y){

 array[y][x]='*';

}

void line(int x1,int y1,int x2,int y2){

 int x,y;
 int dx = x2 - x1;  
 int dy = y2 - y1;  
 int ix = abs(dx);  
 int iy = abs(dy);  
 int inc = max(ix, iy);  
 int plotx = x1;  
 int ploty = y1; 

 x = y = 0;  
 for(int  I = 0; I <= inc ; I++)  
 {  
  x += ix;  
  y += iy;  
  if( x > inc)  
  {  
   x -= inc;  
   plotx += sign(dx);  
  }  
  if( y > inc )  
  {  
   y -= inc;  
   ploty += sign(dy);  
  }  
  drawPoint(plotx, ploty);
  //그리는 함수 ( plotx, ploty); 

 }
}

int main(){

 initial();

 //line( 0,0,10,10 );

 show();


 return 0;
}



http://withwani.springnote.com/pages/159993

브레슨햄 알고리즘


컴퓨터 화면에 선을 빠르게 그리는 방법 중에 하나가 브레슨햄(Bresenhan) 알고리듬이 있습니다. 실수 나누셈을 사용하는 직선 공식보다 정수 계산만을 하는 브레슽핸 알고리듬이 매우 빠르죠.

이번에 임데디드 포럼에 그래픽 관련 문서를 만들면서 브레슨햄 선긋기 알고리듬을 정리해 보았습니다. 포럼에는 동영상까지 올렸으므로 관심있는 분은 방문해 보시기 바랍니다.

브레슨햄(Bresenham)알고리듬

직선의 공식을 사용하여 머릿 속으로 그래프를 그려 보면, 무수히 많은 점을 생각할 수 있읍니다만, 컴퓨터 그래픽에서는 스크린 좌표가 모두 정수이므로, 복잡하고 계산을 느리게 만드는 실수 계산을 정수 계산 만으로도 구현할 수 없을까하는 생각에서 만들어진 것이 브레슨햄 알고리듬입니다.

 

직선의 공식을 이용하여 계산된 좌료값이 소주점 이하 몇개의 자리로 된 실수값을 어렵게 구했다고 하더라도 컴퓨터화면에 출력할 때에는 소수점이하를 모두 버림한단든지 반올림해서 정수로 만들게 됩니다. 이렇게 버려지는 소수점 이하의 복잡한 계산을 브레슨햄 공식을 이용하여 없애 보도록 하겠습니다.

*** 이하의 설명은 dx 가 dy 보다 큰 경우일 때 입니다. ***

사용자 삽입 이미지

 

 

컴퓨터 화면에 직선을 긋기위해 이미 (xi, yi) 좌표에 점을 찍었습니다. 브레슨햄의 기본 원리는 선의 공식에 따라 다음 좌표값을 구하는 것이 아니라 현재 점의 위치에 대해서 어느 좌표에 다음 점을 찍을 지를 판단하는 알고리듬입니다.

 

그림에서 (xi,yi)의 다음 점의 위치는 녹색점(xi+1, yi+1) 보다는 빨강색점(xi+1, yi) 가 실제 점에 가깝습니다. 그렇다면 여기서 녹색점과 빨강색점에 대해 실제 직선의 위치와의 차이 d1, d2를 구해 보겠습니다.

 

d1, d2를 구하는 이유는, d1 < d2 라면 실제 y 점이 yi에 가깝다는 얘기가 되고, yi 에 점을 찍으면 됩니다. 반대로 d1 > d2 라면 yi+1에 점을 찍으면 되기 때문입니다.

 

 

 

즉, 0 < d1-d2 이면 yi+1 에, 0 > d1-d2 이면 yi 에 점을 찍으면되므로 (1) d1 과 d2의 차, 특히 (2) 차이값이 양수인지, 음수인지를 구하면 되겠습니다.

 

사용자 삽입 이미지



d1 = y -yi

여기서 y=m(xi+1) +b 이므로,

d1 = m(xi+1) +b -yi

d2 는,

 

d2 = (yi+1) -y
   = yi +1 -( m(xi+1)+b)
   = yi -m(xi +1) -b +1

두 거리의 차이를 구해 보겠습니다.

 

d1 - d2 = m(xi+1) +b -yi -(yi -m(xi +1) -b +1)
        = m(xi+1) +b -yi -yi +m(xi+1) +b -1
        = 2 m(xi+1) -2yi +2b -1

 

m 은 기울기를 dy/dx 이므로,

 

  d1 - d2 = 2(dy/dx)(xi+1) -2yi +2b -1

 

여기서 다음 점을 찾기 위해서는 두 거리의 차이가 궁굼한 것이 아니라 두 차이에 대한 부호, 즉 양수인지 음수인지만이 필요하므로 정수 나눗셈이 있는 부분을 양편에 dx를 곱해서 없애겠습니다.

 

dx(d1-d2) = 2dy(xi+1) -2dxyi +2dxb -dx
          = 2dyxi +2dy -2dxyi +2dxb -dx

다시 이 공식에서 변수 부분인 xi 또는 yi 가 들어간 부분과 한번 계산되면 다시 계사할 필요가 없는 부분으로 정리해 보겠습니다. 그리고 부호값 만을 생각할 수 있는 변수 pi 로 정리해 보겠습니다.

 

dx(d1 - d2) = pi = 2dyxi +2dy -2dxyi +2dxb -dx
            = 2dyxi -2dxyi +2dy +2dxb -dx
            = 2dyxi -2dxyi +2dy +dx(2b -1)

상수부분인 2dy +dx(2b-1)를 C 로 대치하면,

 

pi = 2dyxi -2dxyi +C   <--- 공식 1

가 됩니다.

 

우리가 이 알고리듬을 이용해서 선을 긋게 되면, 루프를 이용하게 될 것이고, 이전에 계산된 pi 값을 이번 계산에 대입하고 적용할 수 있습니다.

그러므로 다음 pi 값인 pi+1 값을 아래와 같이 구할 수 있습니다.

 

pi+1 = 2dyxi+1 -2dxyi+1 +C

이전 p 값을 계속 참조하여 계산 하므로 pi 와 pi+1 값의 차를 구하겠습니다.

 

pi+1 - pi= 2dyxi+1 -2dxyi+1 +C - 2dyxi +2dxyi -C
        = 2dy(xi+1-xi) - 2dx(yi+1-yi)

여기서 xi+1 와 xi는 서로 이웃하는 점이므로 xi+1 - xi는 1입니다.

그러므로 아래와 같이 정리할 수 있습니다.

 

pi+1 - pi= 2dy - 2dx(yi+1-yi)

이제 pi+1 값만 구한다면,

pi+1 = pi + 2dy - 2dx(yi+1-yi)

아직까지 복잡하게 보이지만 역시 스크린 좌표는 정수이고 yi+1와 yi 의 차이가 0 또는 1이라는 점을 상기한다면,

  • 계산된 pi 값이 양수라면 d1이 더 크므로 다음 점은 현재의 yi 보다 1 만큼 크게되므로,

    pi+1 = pi + 2dy - 2dx

    가 되며,
  • pi 값이 음수라면 d1이 더 작으므로 yi 값과 같아지므로 yi+1 - yi 는 0이 되므로,

    pi+1 = pi + 2dy

    값이 됩니다.
사용자 삽입 이미지





여기서 계산된 pi+1은 다음 루프의 pi 값이 되므로 이를 루프에서 계속 계산되고 다음 계산에 대입된다면 처음 p0 값을 구하고 점을 찍고 다음 pi 값으로 대입하면서 점 위치를 찾아 점을 찍으면 됩니다.

 

p0 구하기

p0값을 구하기 위해 공식 1 에 처음 좌표 (x1, y1)을 대입하고, 다음 예상 좌표를 (x1+1, y1+1/2)로 생각하고 p0을 구합니다..

 

p(x1, y1) = 2dyx1 -2dxy1 +C

p(x1+1, y1+1/2)= 2dy(xi+1) -2dx(yi+1/2) +C

p0  = p(x1+1, y1+1/2) - p(x1, y1)
    = 2dy(xi+1) -2dx(yi+1/2) +C - ( 2dyx1 -2dxy1 +C)
    = 2dyx1 +2dy -2dxy1 -dx -2dyx1 +2dxy1 +C -C
    = 2dy(x1-x1) +2dy -2dx(y1-y1) -dx
    = 2dy -dx

p0 을 구하기 위해 x1 의 다음 좌표는 당연히 1 을 증가한 x1+1 이 되겠지만 , y1 축의 값은 y1 이 될지 y1+1이 될지 모르므로 확률 상의 경우를 1/2로 보고 계산한 것입니다.

 

선을 긋기 전에 필요한 상수 값

  • 최초의 p0 을 구합니다.
  • pi 의 부호 값에 따라 아래의 2가지 값이 필요합니다.
    • 2(dy -dx)
    • 2dy

이후 선을 긋는 루프에서

  • 계산된 p 값이 양수이면,
    • y 좌표값을 1 증가하고,
    • p 값에 2(dy-dx) 값을 더합니다.
  • 음수 이면,
    • p 값에 2dy 만 더합니다.
          #include <stdio.h>
          #include <stdlib.h>
          #include <string.h>        // abs
          
          #include <unistd.h>        // open/close
          #include <fcntl.h>         // O_RDWR
          #include <sys/ioctl.h>     // ioctl
          #include <sys/mman.h>      // mmap PROT_
          #include <linux/fb.h>
          
          int   screen_width;
          int   screen_height;
          unsigned short *fb_mapped;
          
                                   
          void  dot( int x, int y)
          {
             unsigned short *ptr;
          
             ptr   = fb_mapped + screen_width * y + x;
             *ptr  = 0xffff;
          }
          
          void  line( int x1, int y1, int x2, int y2)
          {        
             int      dx, dy;
             int      p_value;
             int      inc_2dy;
             int      inc_2dydx;
             int      inc_value;
             int      ndx;
                             
             dx       = abs( x2 -x1);
             dy       = abs( y2 -y1);
             
             
             if ( dy <= dx)
             {
                inc_2dy     = 2 * dy;
                inc_2dydx   = 2 * ( dy - dx);
                
                if ( x2 < x1)
                {
                   ndx   = x1;
                   x1    = x2;
                   x2    = ndx;
                   
                   ndx   = y1;
                   y1    = y2;
                   y2    = ndx;
                }
                if ( y1 < y2)  inc_value   = 1;
                else           inc_value   = -1;
                   
                dot( x1, y1);
                p_value  = 2 * dy - dx;    
                for (ndx = x1; ndx < x2; ndx++)
                {
                   if ( 0 > p_value)    p_value  += inc_2dy;
                   else
                   {
                      p_value  += inc_2dydx;
                      y1       += inc_value;
                   }
                   dot( ndx, y1);
                }
             }
             else
             {
                inc_2dy     = 2 * dx;
                inc_2dydx   = 2 * ( dx - dy);
                
                if ( y2 < y1)
                {
                   ndx   = y1;
                   y1    = y2;
                   y2    = ndx;
                   
                   ndx   = x1;
                   x1    = x2;
                   x2    = ndx;
                }
                if ( x1 < x2)  inc_value   = 1;
                else           inc_value   = -1;
                   
                dot( x1, y1);
                p_value  = 2 * dx - dy;    
                for (ndx = y1; ndx < y2; ndx++)
                {
                   if ( 0 > p_value)    p_value  += inc_2dy;
                   else
                   {
                      p_value  += inc_2dydx;
                      x1       += inc_value;
                   }
                   dot( x1, ndx);
                }
                
             }
             
          }  
          
          
          int   main( int argc, char **argv)
          {
             int      fb_fd;
             struct   fb_var_screeninfo  fbvar;
             struct   fb_fix_screeninfo  fbfix;
             int      bytes_per_line;
             int      mem_size;
          
             if ( access( "/dev/fb", F_OK))
             {
                printf( "프레임 버퍼 장치가 없습니다.\n");
                return 0;
             }
          
             if ( 0 > ( fb_fd = open( "/dev/fb", O_RDWR)))
             {
                printf( "프레임 버퍼에 접근할 수 없습니다.\n");
                return 0;
          
             }
          
             if ( ioctl( fb_fd, FBIOGET_VSCREENINFO, &fbvar))
             {
                printf( "FBIOGET_VSCREENINFO를 실행하지 못했습니다.\n");
                return 0;
             }
             if ( ioctl( fb_fd, FBIOGET_FSCREENINFO, &fbfix))
             {
                printf( "FBIOGET_FSCREENINFO 실행하지 못했습니다.\n");
                return 0;
             }
          
             screen_width   = fbvar.xres;                    // 스크린의 픽셀 폭
             screen_height  = fbvar.yres;                    // 스크린의 픽셀 높이
             bytes_per_line = fbfix.line_length;             // 한개 라인 당 바이트 개수
          
             mem_size       = bytes_per_line * screen_height;
          
             fb_mapped      = ( unsigned short *)mmap( 0,
                                                    mem_size,
                                                    PROT_READ|PROT_WRITE,
                                                    MAP_SHARED,
                                                    fb_fd,
                                                    0);
          
             
             if ( 5 != argc)
             {
                printf( "사용방법: $]./sample x1 y1 x2 y2 \n");
             }
             else
             {
                line( atoi( argv[1]), atoi( argv[2]), atoi( argv[3]), atoi(argv[4]));
             }
          
             munmap( fb_mapped, mem_size);
             close( fb_fd);
          
             return 0;
          }
          

void bs_BresenhamLine(vector2i s, vector2i e, CImage* img, COLORREF color)
{
 vector2i vStart = s;
 vector2i vEnd = e;
 int dx = vEnd.x-vStart.x;
 int dy = vEnd.y-vStart.y;
 int stepx = 1;
 int stepy = 1;
 if(dx<0)
 {
  dx = -dx;
  stepx = -1;
 }

 if(dy<0)
 {
  dy = -dy;
  stepy = -1;
 }

 int x = vStart.x;
 int y = vStart.y;

 int eps = 0;

 if(dx>dy)
 {
  do 
  {
   //m_vLinelist[m_nLineSize++] = vector2f((float)x,(float)y);
   img->SetPixel(x,y,color);
   if(dx==0)
    break;
   if((eps+=dy) << 1 >= dx)
   {
    y += stepy;
    eps -= dx;
   }
  } while((x+=stepx)!=vEnd.x);
 }
 else
 {
  do
  {
   //m_vLinelist[m_nLineSize++] = vector2f((float)x,(float)y);
   img->SetPixel(x,y,color);
   if(dy==0)
    break;
   if((eps+=dx) << 1 >= dy)
   {
    x += stepx;
    eps -= dy;
   }
  } while((y+=stepy)!=vEnd.y);
 }
}

 
 



브레슨햄 알고리즘  프로그래밍이야기 

2007/03/26 11:08

복사http://blog.naver.com/bbosasi8/110015833947



Bresenham Algorithm 

간단히 말해 선그리는 알고리즘이다. 

(Side Note. 1965년에 발표됐단다 ㅡㅡ; 짱오래뎄네...) 

그냥... 

y = mx + b 
(m은 기울기 y/x, b는 y축을 통과하는 점) 

이렇게 for로 x쭉 돌리면 나온다. 

근데 문제는 기울기에 나누기 and x곱하기 게다가 실수 ㅡㅡ; 

느릴것이 자명하다. 

그래서 나온것이 이 알고리즘이다. 

(브레젠햄, 브레슨햄, 브렌센햄 뭐 다양하게 불리는데 별로 관심없고...) 

간단한 pseudo code로 표현해보자면. 

1. 에러항(error term) 변수를 하나 만들어 0을 집어 넣는다. 

    int errterm = 0; 

2. x와 y의 길이값을 가져온다. 
    int delta_x = x2-x1; // 단, x2>=x1 
    int delta_y = y2-y1; // 단, y2>=y1 

3. delta_x의 절반값을 들고있는다. 
    int half_x = delta_x/2; // 소수점이하는 버린다. 

4. x에 대해 x++씩 루프를 돌리면서 ... 
    y길이를 에러항에 더해주고... 
    에러항이 half_x보다 크다면 y++시켜준다. 

        for( ;x1<=x2;x1++) 
        { 
                errterm += delta_y; 
                 
                if ( errterm > halfx ) 
                { 
                        errterm -= delta_x; 
                        y1++; 
                } 
        } 

나누기, 곱하기~ 이놈들을 없앴다. ^^ 

으흐흐... 

어디선가 긁은 더 깔끔한한 코드 

#define max( x, y) (((x) > (y)) ? (x) : (y)) // 큰수 찾는거 당연히 아시겠줘?  
 
#define abs( x ) (((x) > 0) ? -(x) : (x)) // 절대값.  
 
#define sign( x ) ((x) > 0 ? 1 : ((x) == 0 ? 0: (-1))) // 양수:1, 0, 음:-1  
 
 
두점 ( x, y ) (x2, y2)  
 
dx = x2 - x1;  
 
dy = y2 - y1;  
 
 
ix = abs(dx);  
 
iy = abs(dy);  
 
inc = max(ix, iy);  
 
 
plotx = x1;  
 
ploty = y1;  
 
x = y = 0;  
 
 
for( I = 0; I <= inc ; I++)  
 
{  
 
x += ix;  
 
y += iy;  
 
 
if( x > inc)  
 
{  
 
x -= inc;  
 
plotx += sign(dx);  
 
}  
 
if( y > inc )  
 
{  
 
y -= inc;  
 
ploty += sign(dy);  
 
}  
 
그리는 함수 ( plotx, ploty);  
 

반응형
반응형

복사http://jmpabu.blog.me/70069397777


프로그래밍에 있어서는 기하는

사실적으로 쉬운 부분이다.

그러나 대부분(?)의 인간들은 기하에 대한 문제를

어렵게 생각한다. 물론 나도 마찬가지이다.

기하는 여러 경우로 나눠서 생각해보아야 하기 때문이다.

그러면 우선적으로 기본부터 알고가자.

 

========== 다각현의 면적 ===========

수올을 한다면 대부분은 알고있을 것이다.

다각형의 각 꼭지점의 좌표가 시계방향순으로 했을경우에

(x1,y1), (x2,y2), ... , (xn,yn)이라 하자. (-> n각형)

(혹은 반시계방향도 괜찮다. 또, 삼각형일때는 순서는 상간없다.)

면적 S는 다음과 같이 구한다.

이를 흔히 사선식이라 부른다.

증명은 알아서 해보길 바란다.

 

====== 시계 및 반시계 방향 확인 ======

어느 세 점, (x1,y1), (x2,y2) (x3,y3), 이 있다하자.

이때 이 세 점을 순서대로 이어서 선을 그을 때 이 선이

시계방향으로 돌아가는가, 반시계방향으로 돌아가는가를 아는 것 이다.

 

위의 사선식을 이용하면 쉬게 구할 수 있다.

S = 1/2 |x| 라 해보자. (이 경우에서는 n=3일 때이다.)

i) x<0 ; 이는 시계방향을 의미이다.

ii) x=0; 이는 일직선 상에 세 점이 놓여있음을 의미한다.

iii) x>0; 이는 반시계방향을 의미한다.

증명은 역시 알아서 해보길 바란다.

 

========= 선분 교차 =========

선분교차의 여부에 관한것은 내가 이 블로그에 올려놨으니 그 설명으로도 충분히 이해가 가길 바란다.

 

=========== 점의 위치 ==========

어떤 점 (x0,y0) 이 있다 해보자.

그리도 n각형의 도형 (x1,y1) ~ (xn,yn)있다 하자. (n≥3)

그럴때 (x0,y0)이 위의 도형안에 있는지,

도형 위에 있는지, 또 도형 밖에 있는지를 판별 해 보려고 한다.

 

점이 도형위에 있는지를 판별하는것은 문제가 되지 않는다.

임의의 한 변과 주어진 점으로 사선식을 돌렸을때 0이 나와야하며

점의 좌표범위가 (xi,yi), (x(i+1),y(i+1))의 내부에 위치하기만 한다면

선분위에 그 좌표가 있는셈이다. (물론 방법은 조금 달라도 된다.)

 

그럼 나머지의 경우를 알아보자.

방법은 간단하다.

(x0,y0)에서 오른쪽으로 직선을 그어보자. ((x0,y0) - (∞,y0) 연결)

그 선분과 도형과의 교점갯수를 세어봤을때

짝수이면 점은 도형 바깥에 위치하는 것이며

홀수이면 점은 도형 안쪽에 위치하게 되는 셈이다.

 

셀 때에는 그저 각 선분마다 그 반직선과 만나면 갯수를 증가시켜주면 된다.

그러나 교점을 셀 때에는 어떤 경우는 세어야 하며

어떠한 경우는 세지 말아야 하는 경우가 생기게 된다.

다음 그림을 봐보자.

 

1,3번과 같은 경우는 만나지 않은것으로,

2,4번과 같은 경우는 1번 만난것으로 체크를 해 쥐야 한다.

그러므로

위와같은 경우에서 첫줄일 경우에만 한번 체크해 주면 되겠다.

반응형
반응형

 

블로그 이미지

3DMP engines

3D그래픽스 물리 수학, 프로그래밍 GPU Shader 게임엔진 알고리즘 디자인패턴 matlab etc.. 


결론적으로 이것은   인 결과 즉 사원수3개의 곱으로(또는 p 가 w=0 인 벡터여도 상관없다) 나온 결과들을 

행렬로 옮겨놓은것이다






이하내용은  지금은 알수 없는 어디선가 퍼온자료



쿼터니언은 복소수의 확장으로 i, j, k 3개의 허수와 w, x, y, z 4개의 실수부로 이루어져 있다.

즉 하나의 스칼라와 3개의 벡터 ==> 4개의 구성 요소로 이루어진 복소수를 말한다.

허수 i, j, k는 i * i = -1의 성질을 가진다.

 = w + xi + yj + zk
 

= sq + vq

 

 = (sq , vq)

 

 = [ w , (x, y, z) ]

여기서 w는 스칼라 v = (x, y, z)는 벡터이다.

쿼터니언 크기  ||q|| = Norm(q) = sqrt(w+ x2 + y2 + z2)

단위 쿼터니언 성질  w+ x2 + y2 + z= 1

단위 쿼터니언은 (x, y, z)요소를 임의의 축, w요소를 회전 각도로 하여 4차원 공간에 표현 할 수 있다.

그림으로 간단하게 표현 하면 벡터 축 A를 중심으로 회전하는 θ는

 

사원수를 이용한 벡터 회전 변환

벡터 p를 사원수 q로 회전할 때 공식과 행렬에 대한 변환은 다음과 같다.

 

 =

|
|
|
|
|
|

1 - 2Y2 - 2Z2

2XY + 2ZW

2XZ - 2YW

2XY - 2ZW

1 - 2X2 - 2Z2

2YZ + 2XW

2XZ + 2YW

2YZ - 2XW

1 - 2X2 - 2Y2

|
|
|
|
|
|

 

쿼트니언을 행렬 변환하는 함수

//-----------------------------------------------------------------------------

//예전 다이렉트X 버전에 d3dmath.cpp 파일에 있는 소스이다.

//-----------------------------------------------------------------------------

VOID D3DMath_MatrixFromQuaternion( D3DMATRIX& mat, FLOAT x, FLOAT y, FLOAT z, FLOAT w )

{

    FLOAT xx = x*x; FLOAT yy = y*y; FLOAT zz = z*z;

    FLOAT xy = x*y; FLOAT xz = x*z; FLOAT yz = y*z;

    FLOAT wx = w*x; FLOAT wy = w*y; FLOAT wz = w*z;

 

    mat._11 = 1 - 2 * ( yy + zz );

    mat._12 =    2 * ( xy - wz );

    mat._13 =    2 * ( xz + wy );

 

    mat._21 =    2 * ( xy + wz );

    mat._22 = 1 - 2 * ( xx + zz );

    mat._23 =    2 * ( yz - wx );

 

    mat._31 =    2 * ( xz - wy );

    mat._32 =    2 * ( yz + wx );

    mat._33 = 1 - 2 * ( xx + yy );

 

    mat._14 = mat._24 = mat._34 = 0.0f;

    mat._41 = mat._42 = mat._43 = 0.0f;

    mat._44 = 1.0f;

}

 

행열을 쿼트니언으로 변환하는 함수

VOID D3DMath_QuaternionFromMatrix( FLOAT& x, FLOAT& y, FLOAT& z, FLOAT& w, D3DMATRIX& mat )

{

    if( mat._11 + mat._22 + mat._33 > 0.0f )

    {

        FLOAT s = (FLOAT)sqrt( mat._11 + mat._22 + mat._33 + mat._44 );

 

        x = (mat._23-mat._32) / (2*s);

        y = (mat._31-mat._13) / (2*s);

        z = (mat._12-mat._21) / (2*s);

        w = 0.5f * s;

    }

    else

    {

 

 

    }

    FLOAT xx = x*x; FLOAT yy = y*y; FLOAT zz = z*z;

    FLOAT xy = x*y; FLOAT xz = x*z; FLOAT yz = y*z;

    FLOAT wx = w*x; FLOAT wy = w*y; FLOAT wz = w*z;

 

    mat._11 = 1 - 2 * ( yy + zz );

    mat._12 =    2 * ( xy - wz );

    mat._13 =    2 * ( xz + wy );

 

    mat._21 =    2 * ( xy + wz );

    mat._22 = 1 - 2 * ( xx + zz );

    mat._23 =    2 * ( yz - wx );

 

    mat._31 =    2 * ( xz - wy );

    mat._32 =    2 * ( yz + wx );

    mat._33 = 1 - 2 * ( xx + yy );

 

    mat._14 = mat._24 = mat._34 = 0.0f;

    mat._41 = mat._42 = mat._43 = 0.0f;

    mat._44 = 1.0f;

}

 

 

 

반응형
반응형

블로그 이미지

3DMP engines

3D그래픽스 물리 수학, 프로그래밍 GPU Shader 게임엔진 알고리즘 디자인패턴 matlab etc..




[평행이동 타원과 선분의 교차판정]

 

 



 

* 설명 : 두 점을 지나는 직선의 y 값을 평행이동 타원의 방정식에 대입하여 x 에 대해 정리하면

           직선과 타원의 교차되는 해를 구할 수 있으며 이 범위가 선분의 범위에 포함된다면 교차된것

           올린 글중 

 





 

 

 

 

 

반응형
반응형


첨부파일 : squ-curve.ppt






http://ko.wikipedia.org/wiki/%ED%83%80%EC%9B%90





타원

위키백과, 우리 모두의 백과사전.
두 점 F1과 F2를 초점으로 갖는 타원.
원뿔을 평면으로 잘라 얻은 타원.

타원(楕圓)이란 평면 위의 두 정점으로부터의 거리의 합이 일정한 점의 집합으로 만들어지는 곡선을 이르는 기하학 용어이다. 타원을 정의하는 기준이 되는 두 정점은 타원의 초점(focus)으로 불린다. 타원 상에서 두 개의 초점으로부터의 거리가 같은 두 점을 잇는 선분을 단축(짧은 축)이라고 하며, 두 개의 초점으로부터의 거리의 차가 최대인 두점을 잇는 선분을 타원의 장축(긴 축)이라고 한다. 또한, 이 두 선분의 반을 짧은반지름(semiminor axis), 긴반지름(semimajor axis)이라고 한다.

[편집]
두 초점이 가까울 수록 타원은
 에 가까워지며, 두개의 초점이 일치했을 때의 타원은 원이 된다. 그 때문에 원은 타원의 특수한 경우라고 생각할 수도 있다.타원의 성질

[편집]타원의 작도

위의 정의를 따르면 두 개의 초점에 실을 고정해, 실을 팽팽하게 유지하면서 필기구를 실에 걸쳐서 움직여서 그릴 수 있다. 이 외, 타원 컴퍼스, 타원 템플릿등을 사용하여 작도할 수 있다.

[편집]타원의 방정식

2차원 직교좌표계에서 원점 O가 타원의 장축과 단축의 교점이며, 각 축이 x축이나 y축과 일치할 때의 타원의 방정식은 다음과 같이 간단히 표현된다.

\frac{x^{2}}{a^{2}} + \frac{y^{2}}{b^{2}} = 1

장축이 x축과 일치할 때, 2 a는 타원의 장축의 길이, 2 b는 단축의 길이가 된다. 같은 타원을 호도각에 따른 매개변수 t로 나타내면 다음과 같다.

x = a\,\cos t
y = b\,\sin t
0 \leq t < 2\pi

x축으로 α만큼, y축으로 β만큼 평행이동한 타원의 방정식은 다음과 같다.

\frac{(x-\alpha)^{2}}{a^{2}} + \frac{(y-\beta)^{2}}{b^{2}} = 1

[편집]타원의 넓이

타원의 긴반지름이 a이고 짧은반지름이 b인 타원의 넓이는 \pi ab 이다.

[편집]이심률

 이 부분의 본문은 이심률입니다.

타원의 찌그러진 정도를 나타내는 이심률  E=\frac {e} {a} 는 다음과 같이 정의된다.

E = \sqrt{1 - \frac{b^2}{a^2}}

은 이심률이 0인 경우이고, 이심률이 작을수록 원에 가깝다.

[편집]타원의 성질

한 초점에서 출발한 빛이 진행하다가 타원의 어느 한점을 만나면 이때 빛은 페르마의 최소 시간 원리를 따르므로 타원에서 반사되고 그 후 빛은 타원의 다른 초점을 지난다.

반응형

'수학 (Mathematics) > 3D수학' 카테고리의 다른 글

쿼터니언<->행렬 변환 함수 소스  (0) 2012.11.02
[2D] 평행이동 타원과 선분의 교차판정  (0) 2012.11.02
원과 선분의 충돌  (0) 2012.11.02
[2D] 두 선분의 교차판정  (0) 2012.11.02
NDC 공간이란  (0) 2012.11.02
반응형

반응형

'수학 (Mathematics) > 3D수학' 카테고리의 다른 글

[2D] 평행이동 타원과 선분의 교차판정  (0) 2012.11.02
타원 그리기  (0) 2012.11.02
[2D] 두 선분의 교차판정  (0) 2012.11.02
NDC 공간이란  (0) 2012.11.02
베지어 곡선(Bezier Curve) 유도와 설명  (1) 2012.11.02
반응형

일본 사이트의 내용인데 구글 번역기로 번역한것
일어 번연은 그럭저럭 괜찮군... ㅋ
 
http://www5d.biglobe.ne.jp/~tomoya03/shtml/algorithm/Intersection.htm
 
§ Algorithm §


☆ 더 쉽게 - 선 교차 판정 - ☆

여기에서는 선분 교차 판정의 정석이라 할 방법을 소개하고 있습니다.
선분과 직선 간과 소중한 정의입니다.

직선은 한 2 점을지나는선이고
선분은 한 2 점을연결하는선이다.

교차 판정에 대한 점 A, B, C, D, 선분 AB와 선분 CD의 교차를 생각하고 있습니다. 먼저 '선 교차 판정'의 전통적인

"교차점을 찾아 그 교차점이 2 개의 세그먼트의 범위에 있는지 조사한다"

라는 생각을 다른 해석으로 바꿉니다.
2 선이 교차하고있다는 것은

"점 A, B를 지나는 직선이 선분 CD와 교차하며
점 C, D를 지나는 직선이 선분 AB와 교차하고있다 "


로 해석할 수 있습니다. 그래서 선과 선의 교차점은 다음과 같이 확인합니다.

"선을 경계로 선분을 구성하는 2 가지 사항이
직선에 양쪽에 존재할 때, 직선과 선분은 교차한다 "


그런 다음 그 점이 직선에 대해 어느 편에있는지를 묻는 방법을 알아보겠습니다.
y = ax + b라는 직선 =를 부동로 대체
y> ax + b, y <ax + b라는 영역을 나타내는식이 있었다면, 이들 3 개식이 그려진 도형 영역은 다음과 같이 나타낼 수 있습니다.

여기서 2 개의 식을 왼쪽에 移項하여

y - ax - b> 0
y - ax - b <0

로 할 수 있습니다. 있는 점이 직선에 대해 어느 편에 있는지 필요하다면 직선의 방정식에 그 문제에 관해서 (X, Y)를 할당하고 결과 얻어진 값이 양수인지 음수인지에 따라 알 수 있습니다. 양의 경우 한 지점은 직선의 위쪽에 음수이면 한 지점은 직선의 아래 부분에 위치한다는 것을 알 수 있습니다. 직선의 양쪽 (위쪽과 아래쪽)에 점이 있으면 교차하기 때문에, 직선과 선분의 교차 판정을 위해서는 선분을 구성하는 2 개의 점을 직선의 방정식에 대입하여 얻은 값 부호가 서로 다른 (혹은 0) 여부를 조사하면 좋은 것입니다. 다른 경우에 (서로를 곱한 <0) 교차하고 있다고 판정할 수 있습니다.
이것을 구체적으로 식 화해보십시오.
점 A, B의 좌표를 A (x1, y1), B (x2, y2) 로,이 2 가지를 지나는 직선과
점 C, D의 좌표, C (x3, y3), D (x4, y4) 을 잇는 선분을 생각합니다.
점 A (x1, y1), B (x2, y2)를 지나는 직선 AB의 방정식은

y = x * (y1 - y2) / (x1 - x2) + y1 - x1 * (y1 - y2) / (x1 - x2)

로 나타낼 수 있습니다. 나눗셈은 0으로 나누기 또는 오버플로가 무서워 위해 피하기 때문에, 양변에 (x1 - x2)를 걸고 다음과 같이 변형합니다.

y * (x1 - x2) = x * (y1 - y2) + y1 * (x1 - x2) - x1 * (y1 - y2)

이것을 더욱 단순화하고, 왼쪽에 수집합니다.

(x1 - x2) * (y - y1) + (y1 - y2) * (x1 - x) = 0

이것은 점 A (x1, y1), B (x2, y2)를 지나는 직선의 방정식입니다.

이제이 방정식에 점 C (x3, y3), D (x4, y4)을 할당하고 그 부호를 검사하여 직선과 선분의 교차 판정을 할 수 있습니다.
점 C를 할당
tc = (x1 - x2) * (y3 - y1) + (y1 - y2) * (x1 - x3)
점 D를 할당
td = (x1 - x2) * (y4 - y1) + (y1 - y2) * (x1 - x4)

교차 = 2 개의 식의 부호가 다르다는 것을 수식으로 표현하면,

tc * td <0

과 같습니다 다음 코드로 판정 가능합니다. 시저하면 1 줄은 모르지만,
생각 자체는 One Line입니다.

'구조
Private Type POINT x As Double
    y As Double
End Type

'좌표 p1, p2을 지나는 직선과 좌표 p3, p4을 잇는 선이 교차하는지 확인
Private Function intersect (p1 As POINT, p2 As POINT, P3 As POINT, p4 As POINT) as Boolean

    If (((p1.x - p2.x) * (p3.y - p1.y) + (p1.y - p2.y) * (p1.x - p3. x)) * _ ((p1.x - p2.x) * (p4.y - p1.y) + (p1.y - p2.y) * (p1.x - p4.x))> 0 #) Then
        '교차하지 않는
        intersect = False
        Exit Function
    End If
    '교차
    intersect = True
End Function

그리고, 선분 AB와 직선 CD에 대해서도 같은 조사를 사용하여

ta = (x3 - x4) * (y1 - y3) + (y3 - y4) * (x3 - x1)
tb = (x3 - x4) * (y2 - y3) + (y3 - y4) * (x3 - x2)

ta * tb <0

위와 함께, 2 가지 조건 판정하는 경우, 2 개의 선분의 교차 판정을 할 수 있습니다.

'구조
Private Type POINT x As Double
    y As Double
End Type

'좌표 p1, p2를 잇는 선과 좌표 p3, p4을 잇는 선이 교차하는지 확인
'그러나 선이 겹치는 경우 ( 3 점, 4 점이 일직선상에있다), "교차하고 있지 않다"라고 판정합니다.
Private Function intersection (p1 As POINT, p2 As POINT, P3 As POINT, p4 As POINT) as Boolean
    
    If (((p1.x - p2.x) * (p3.y - p1.y) + (p1.y - p2.y) * (p1.x - p3.x)) * _ ((p1.x - p2.x) * (p4.y - p1.y) + (p1.y - p2.y) * (p1 x - p4.x)) "0 #) Then
        If (((p3.x - p4.x) * (p1.y - p3.y) + (p3.y - p4.y) * (p3.x - p1.x)) * _ ((p3.x - p4.x) * (p2.y - p3.y) + (p3.y - p4.y) * (p3.x - p2.x)) " 0 #) Then
            intersection = True
            Exit Function
        End If
    End If
    intersection = False

End Function

이 판정은 선분들이 겹치는 경우 (3 점 또는 4 점이 일직선상에있다), "교차하고 있지 않다"라고 판정합니다. 이것을 "교차한다"고 판정하고 싶은 경우에 대해서는더 빠르고 - 선 교차 판정 -를 참조하십시오. 위의 알고리즘만으로는이를 판정하는 것은 조금 어렵습니다.


(곱셈에 대한 오버플로 및 정수와 부동 소수점)

위 코드는 부동 소수점 연산에서 실시하고 있지만 실제로이 작업을 Windows 그리기 등에 사용하는 경우에는 정수 계산만으로 가능하며, 부동 소수점 대신 Long 정수를 사용하는 것이 빠르게 처리할 수 있기 때문에, 그 쪽이 좋을지도 모릅니다. 만약, 판정하려는 선의 점이 엄청나게 큰 경우, 곱셈에 대한 오버플로가 우려되기 때문에 전체 규모 자체를 작게하여 부동 소수점 계산을 할 필요가 있습니다. 그럴 때 선언하는 변수를 변경하면 유효한이 계산 방법은 아주 편리 뛰어나다고 생각합니다.

아래의 예제에서는 정수 버전을 사용하고 있습니다.


(참고로)

대부분의 참고서이 교차 판정을

"점 A, B를 지나는 직선과 반점 C의 위치 관계에 관하여, ABC 순서별로 점이 시계 방향 또는 시계 반대 방향으로 위치하고있는가라는 것을 알고있다"

와 같이 기술하고 설명하고 있다고 생각합니다. 위의 설명은이 방법을 증명 형식에 가서 보았습니다.


(참조)

'알고리즘 C 제 3 권;
野平 코헤이, 별 군수, 사토 Drug, 타구치 동쪽 공역
현대 과학사

'알고리즘과 데이터 구조』
강촌 준 아키라, 上坂 吉則, 아사 세종 바다, 아리사 마코토, 니시 무라 슌스케
実教出版


(샘플 프로그램의 동작 확인)

기종PC - 9821V13S
OSWindows95
개발 도구Visual Basic Ver.4.0
업데이트 :00/07/22

다운로드 easyCross.lzh(2.86KB)

Visual Basic Ver.5.0, Ver.6.0 잘 작동한다고 생각합니다.
또한,이 코너에 게재되는 프로그램 코드 및 프로그램 파일로 인해 발생하는 손해 등에 대해서 책임을 질 수 없습니다. 

★이 선의 교차는 다양한 작업에 사용할 수 있다고 생각합니다. 본 소스 문서 배포 전재는 금지 입니다만 게재되는 프로그램 코드 및 프로그램 파일은 각자의 책임하에 자유롭게 배포달라고해도됩니다. 그 때, 본 사이트를 소개해 주시면 대단히 기쁩니다.


Algorithm 인덱스 화면


http://www5d.biglobe.ne.jp/~tomoya03/shtml/algorithm/IntersectionEX.htm

 

'構造体
Private Type POINT
    x As Double
    y As Double
End Type

'座標 p1,p2 を結ぶ線分と座標 p3,p4 を結ぶ線分が交差しているかを調べる
'ただし、線分が重なっている場合(3点,4点が一直線上にある)、「交差している」、と判定します。
Private Function intersectionEX(p1 As POINT, p2 As POINT, _ 
                               p3 As POINT, p4 As POINT) As Boolean
    'x座標によるチェック
    If (p1.x >= p2.x) Then
        If ((p1.x < p3.x And p1.x < p4.x) Or (p2.x > p3.x And p2.x > p4.x)) Then
            intersectionEX = False: Exit Function
        End If
    Else
        If ((p2.x < p3.x And p2.x < p4.x) Or (p1.x > p3.x And p1.x > p4.x)) Then
            intersectionEX = False: Exit Function
        End If
    End If
    'y座標によるチェック
    If (p1.y >= p2.y) Then
        If ((p1.y < p3.y And p1.y < p4.y) Or (p2.y > p3.y And p2.y > p4.y)) Then
            intersectionEX = False: Exit Function
        End If
    Else
        If ((p2.y < p3.y And p2.y < p4.y) Or (p1.y > p3.y And p1.y > p4.y)) Then
            intersectionEX = False: Exit Function
        End If
    End If
    
    If (((p1.x - p2.x) * (p3.y - p1.y) + (p1.y - p2.y) * (p1.x - p3.x)) * _
        ((p1.x - p2.x) * (p4.y - p1.y) + (p1.y - p2.y) * (p1.x - p4.x)) > 0#) Then
        intersectionEX = False: Exit Function
    End If
    If (((p3.x - p4.x) * (p1.y - p3.y) + (p3.y - p4.y) * (p3.x - p1.x)) * _
        ((p3.x - p4.x) * (p2.y - p3.y) + (p3.y - p4.y) * (p3.x - p2.x)) > 0#) Then
        intersectionEX = False: Exit Function
    End If
    intersectionEX = True

End Function

반응형
반응형

  • ttp://smilewjp.springnote.com/pages/1753430

  • 투영(Projection)

  • 시야 영역을 양끝 모서리점이(-1,-1,-1)과 (1,1,1)의 좌표를 가지는 단위 정육면체로 변환하는것. 이러한 단위 정육면체를 정규 시야 영역이라고 한다. 대표적인 두가지 투영 방법으로 직교투영(orthographic projection)과 원근 투영(perspective projection)이 있다.
    직교 투영에서 시야 영역은 보통 직사각형 상자 모양이고, 직교 투영에 의해 이러한 시야 볼륨은 단위 정육면체로 변환된다. 직교 투영의 주된 특징은 평행선이 변환 후에도 평행을 유지한다는 것이다. 이 변환은 평행 이동과 크기 변환의 조합으로 표현된다.
    원극투영은 물체가 카메라에서 멀이질수록 투영한 후에 더 작게 보인다. 또한 평생선은 수평선에서 한 점으로 수렴할 수 도 있다. 그러므로 원근 투영변환은 인간이 물체의 크기를 인지하는 방법을 흉내낸 것이라고 할 수 있다.
    직교투영과 원근 투영 변환은 모두 4*4 행렬로 구성될 수 있으며, 변환후에 모델은 (NDC)정규화된 장치 좌표계에 놓여있다라고 한다.
  •  


     

    - 정규 좌표계(NDCS : Normalized Device Coordinate System, 정규화 장치 좌표계)
       * 정규화(normalization)란? : 어떤 값을 1을 기준으로 상대적으로 표시하는 행위
       * 절단 좌표계의 동차 좌표(x,y,z,w)를 3차원 좌표(x/w, y/w, z/w, 1)로 변환하는 원근분할을 가한 좌표 -> 2D 정규 좌표(소수점 정밀도)

    반응형

    + Recent posts