포스트

[ Opengl ] View Transform

View transform


변환을 사용하여 물체의 위치를 변환한다.

카메라 공간


1. 가상 카메라

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
	//카메라(눈)의 위치
	Vector4 eye(5.0f, 0.0f, 5.0f);
	//카메라의 초점(참조 위치)
	Vector4 at(0.0f, 0.0f, 0.0f);
	// 카메라의 위쪽 방향 지정(x=1이면 x축으로 누워있고, y=1이면 y축을 중심으로 세워져있음
	Vector4 upVector(0.0f, 1.0f, 0.0f);
	
	Vector4 a;
	a.x = 0;
	a.y = 0;
	a.z = 1;
	a.w = 1;
	
	Vector4 forward = eye - at;
	forward = normalize(forward);

	// compute the left vector
	Vector4 left = crossProduct(upVector, forward); // cross product
	left = normalize(left);

	// recompute the orthonormal up vector
	Vector4 up = crossProduct(forward, left);    // cross product
	up = normalize(up);


2. 행렬, 벡터 기능 추가

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
Vector4 input(float x, float y, float z)
{
	Vector4 ret;
	ret.x = x;
	ret.y = y;
	ret.z = z;
	return ret;
}

float operator*(Vector4 v1, Vector4 v2) //내적 구하기(스칼라 곱) 
{ 
	Vector4 ret;
	ret.x = v1.x * v2.x;
	ret.y = v1.y * v2.y;
	ret.z = v1.z * v2.z;
	return ret.x + ret.y +ret.z; 
}

float innerCos(Vector4 v1, Vector4 v2) //각도 구하기 
{ 
	float cos = (v1 * v2) / (magnitude(v1) * magnitude(v2));
	return cos; 
} 

Vector4 normalize(Vector4 v) // 정규화(단위벡터로 만들기) 
{ 
	Vector4 normal; 
	float magn = magnitude(v);
	normal.x = v.x / magn;
	normal.y = v.y / magn;
	normal.z = v.z / magn;
	return normal; 
} 

float magnitude(Vector4 v) // 벡터 크기 
{ 
	auto magnitude = sqrt(pow(v.x, 2) + pow(v.y, 2) + pow(v.z, 2)); 
	return magnitude; 
} 

static double Seta(float cos) //세타값 구하기 각도(디그리) 
{ 
	return acos(cos) * (180 / PI);
} 

static Vector4 proj(Vector4 v1, Vector4 v2) // 방향(normal) * 크기(magnitude = Proj(V1) 
{ 
	Vector4 ret; 
	ret.x = ((v1 * v2) / (v2 * v2)) * v2.x;
	ret.y = ((v1 * v2) / (v2 * v2)) * v2.y;
	ret.z = ((v1 * v2) / (v2 * v2)) * v2.z;
	return ret; 
} 
static Vector4 orthogonalProjection(Vector4 v1, Vector4 proj) // 직교화 
{
	Vector4 ortho; 
	ortho = v1 - proj;
	return ortho; 
} 

Vector4 crossProduct(Vector4 v1, Vector4 v2) //외적 
{
	Vector4 cross;
	cross.x = (v1.y * v2.z) - (v1.z * v2.y);
	//cross.y = (v1.x * v2.z - v1.z * v2.x);
	cross.y = (v1.z * v2.x) - (v1.x * v2.z);
	cross.z = (v1.x * v2.y) - (v1.y * v2.x);
	return cross;
}


3. 카메라 변환

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
Matrix4 RotateMatrix(Vector4 v, float angle)
{
    Matrix4 ret = identityMatrix();
    float c = cos(angle * PI / 180);
    float s = sin(angle * PI / 180);

    ret.arr[0][0] = c + (v.x * v.x) * (1 - c);          
    ret.arr[0][1] = (v.x * v.y * (1 - c)) - v.z * s;    
    ret.arr[0][2] = (v.x * v.z * (1 - c)) + v.z * s;
    ret.arr[1][0] = (v.y * v.x * (1 - c)) + v.z * s;    
    ret.arr[1][1] = c + (v.y * v.y * (1 - c));          
    ret.arr[1][2] = (v.y * v.z * (1 - c)) - v.x * s;
    ret.arr[2][0] = (v.z * v.x * (1 - c)) - v.y * s;    
    ret.arr[2][1] = (v.z * v.y * (1 - c)) - v.x * s;    
    ret.arr[2][2] = c + (v.z * v.z * (1 - c));
    return ret;
}


 Matrix4 lookAt(Vector4 eye, Vector4 at, Vector4 upVector)
 {
     // compute the forward vector from target to eye
     Vector4 forward = eye - at;
     forward = normalize(forward); // make unit length
     // compute the left vector
     Vector4 left = crossProduct(upVector,forward); // cross product
     left = normalize(left);
     // recompute the orthonormal up vector
     Vector4 up = crossProduct(forward,left); // cross product
     up = normalize(up);

     // set rotation part, inverse rotation matrix: M^-1 = M^T for Euclidean transform
     Matrix4 R = identityMatrix();
     R.arr[0][0] = left.x; 
     R.arr[0][1] = left.y;      
     R.arr[0][2] = left.z;      
     R.arr[0][3] = -left.x * eye.x - left.y * eye.y - left.z * eye.z;
     R.arr[1][0] = up.x;          
     R.arr[1][1] = up.y;        
     R.arr[1][2] = up.z;        
     R.arr[1][3] = -up.x * eye.x - up.y * eye.y - up.z * eye.z;
     R.arr[2][0] = forward.x;     
     R.arr[2][1] = forward.y;   
     R.arr[2][2] = forward.z;   
     R.arr[2][3] = -forward.x * eye.x - forward.y * eye.y - forward.z * eye.z;
     return R;
 }

 const float degree = 3.141593f / 180.0f;

 Matrix4 xlookatRotate(float angle)
 {
     Matrix4 R = identityMatrix();

     float c = cos(angle * degree);
     float s = sin(angle * degree);
     float m1 = R.arr[0][0], m2 = R.arr[0][1],
           m5 = R.arr[1][0], m6 = R.arr[1][1],
           m9 = R.arr[2][0], m10 = R.arr[2][1],
           m13 = R.arr[3][0], m14 = R.arr[3][1];

     Matrix4 ret;
     ret.arr[0][0] = m1 * c + m2 * -s;
     ret.arr[0][1] = m1 * s + m2 * c;
     ret.arr[1][0] = m5 * c + m6 * -s;
     ret.arr[1][1] = m5 * s + m6 * c;
     ret.arr[2][0] = m9 * c + m10 * -s;
     ret.arr[2][1] = m9 * s + m10 * c;
     ret.arr[3][0] = m13 * c + m14 * -s;
     ret.arr[3][1] = m13 * s + m14 * c;
     return ret;
 }


4. 렌더링

1
2
3
4
5
6
7
8
9
10
11
12
void Renderer::render()
{
	clearCheckImage();
	Matrix4 mv = m_view * m_world;
	applyMatrix(mv);
	for (int i = 0; i < m_nNumFace; i++)
	{
		clearEdgetable();
		buildEdgetable(i);
		fill(m_face[i].m_color);
	}
}


4. 입력

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
void keyboard(unsigned char key, int x, int y)
{
	switch (key) {
	case 'q':
		g_renderer.m_world = scaleMatrix(0.5f, 0.5f, 0.5f) * g_renderer.m_world;
		glutPostRedisplay();
		break;
	case 'i':
		g_renderer.m_world = xRotateMatrix(30.0f) * g_renderer.m_world;
		glutPostRedisplay();
		break;
	case 'o':
		g_renderer.m_world = yRotateMatrix(30.0f) * g_renderer.m_world;
		glutPostRedisplay();
		break;
	case 'p':
		g_renderer.m_world = zRotateMatrix(30.0f) * g_renderer.m_world; 
		glutPostRedisplay();
		break;
	case 'l':
		g_renderer.m_view = lookAt(eye, at, upVector);
		glutPostRedisplay();
		break;
	case 'w':
		seta -= 10.0f;
		eye = xRotateMatrix(seta) * zRotateMatrix(0.5f) * scaleMatrix(length, length, length) * a;
		g_renderer.m_view = lookAt(eye, at, upVector);
		glutPostRedisplay();
		break;
	case 's': 
		seta += 10.0f;
		eye = xRotateMatrix(seta) * zRotateMatrix(0.5f) * scaleMatrix(length, length, length) * a;
		g_renderer.m_view = lookAt(eye, at, upVector);
		glutPostRedisplay();
		break;
	case 'a':
		seta += 10.0f;
		eye = yRotateMatrix(seta) * xRotateMatrix(0.5f) * scaleMatrix(length, length, length) * a;
		g_renderer.m_view = lookAt(eye, at, upVector);
		glutPostRedisplay();
		break;
	case 'd':
		seta -= 10.0f;
		eye = yRotateMatrix(seta) * xRotateMatrix(0.5f) * scaleMatrix(length, length, length) * a;
		g_renderer.m_view = lookAt(eye, at, upVector);
		glutPostRedisplay();
		break;
	case 27:
		exit(0);
		break;
	default:
		break;
	}
}


이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.