{
9과에 오신 것을 환영합니다. 이제 OpenGL에 대해 잘 이해하셨을 것입니다.
"CKER: 그렇지 않다면 내 번역가의 잘못임에 틀림없어요..."
(Myling 추가: 내 죄가 더 크네요, 하하)
OpenGL 창 설정에 대한 모든 세부 사항을 배웠습니다.
회전하는 개체에 빛과 색상 혼합(투명도)을 매핑하고 추가하는 방법을 알아보세요.
이 강의는 중급 튜토리얼로 간주되어야 합니다.
3D 장면 주위로 비트맵을 이동하고 비트맵에서 검은색 픽셀을 제거하는 방법(색상 혼합 사용)을 배웁니다.
다음으로 흑백 질감을 색칠하고 마지막으로 풍부한 색상을 만드는 방법을 배우게 됩니다.
그리고 서로 다른 색상의 텍스처를 서로 혼합하여 간단한 애니메이션 효과를 얻을 수 있습니다.
첫 번째 강의의 코드를 기반으로 수정해 보겠습니다. 먼저 프로그램 소스 코드 시작 부분에 몇 가지 변수를 추가합니다.
명확성을 위해 전체 코드를 다시 작성했습니다.
}
바르
h_RC: HGLRC; // 렌더링 컨텍스트(쉐이딩 설명 테이블).
h_DC: HDC; // 장치 컨텍스트(장치 설명 테이블)
h_Wnd: HWND; // 창 핸들
h_Instance: HINST; // 프로그램 인스턴스(인스턴스).
키 : Array[0..255] Of Boolean // 키보드 루틴용 배열;
{다음 줄이 새로 추가되었습니다.
Twinkle 및 tp는 부울 변수이므로 TRUE 또는 FALSE로만 설정할 수 있습니다.
반짝임은 깜박임 효과가 활성화되어 있는지 추적하는 데 사용됩니다.
tp는 'T' 키가 눌렸는지 또는 놓였는지 확인하는 데 사용됩니다.
(누르면 tp=TRUE, 놓으면 tp=FALSE).}
Twinkle : 부울; // 반짝이는 별 (신규)
tp : 부울; // 'T'가 눌렸나요? (신규)
{이제 구조를 만들어 보겠습니다.
구조라는 단어가 무섭게 들리지만 그렇지 않습니다. (델파이의 레코드형입니다.)
구조는 유사한 데이터의 더 큰 조합을 표현하기 위해 간단한 유형의 데이터(및 변수 등) 세트를 사용합니다.
우리는 별을 추적하고 있다는 것을 알고 있습니다.
아래에서 별을 볼 수 있습니다.
각 별에는 세 가지 정수 색상 값이 있습니다. 하나는 빨간색(r), 하나는 녹색(g), 하나는 파란색(b)입니다.
또한, 각 별은 화면 중심으로부터 서로 다른 거리에 있으며,
그리고 화면 중심을 원점으로 하여 360도 어느 각도든 가능합니다.
거리를 추적하기 위한 dist의 부동 소수점 수입니다.
부동 소수점 각도 수는 별의 각도 값을 추적합니다.
그래서 우리는 일련의 데이터를 사용하여 화면에 있는 별의 색상, 거리, 각도를 설명했습니다.
불행하게도 우리는 하나 이상의 별을 추적하고 있습니다.
하지만 빨간색 값 50개, 녹색 값 50개, 파란색 값 50개, 거리 값 50개를 만들 필요는 없습니다.
50개의 각도 값을 입력하고 배열 별을 만듭니다. }
유형
stars = Record // 별이라는 이름의 별에 대한 구조를 만듭니다.
r, g, b: 정수 // 별의 색;
dist: GLfloat; //중심에서 별까지의 거리
angle: GLfloat; //별의 현재 각도
끝;
바르
star : Array[0..49] Ofstars // 'stars' 구조를 사용하여 50개의 요소를 포함하는 'star' 배열을 생성합니다.
{다음으로 여러 추적 변수를 설정합니다.
관측자로부터 별까지의 거리변수(줌),
우리가 별을 보는 각도(기울기),
그리고 반짝이는 별이 Z축을 중심으로 회전하게 만드는 가변 스핀.
루프 변수는 별 50개를 그리는 데 사용됩니다.
텍스처[1]은 흑백 텍스처를 저장하는 데 사용됩니다.
더 많은 텍스처가 필요하다면,
사용하기로 결정한 텍스처 수만큼 텍스처 배열의 크기를 늘려야 합니다.
}
Zoom : GLfloat = -15.0; // 관찰자로부터 별까지의 거리
Tilt : GLfloat = 90.0; // 별의 기울기
spin : GLfloat; // 반짝이는 별의 회전
loop : GLuint; // 전역 루프 변수
텍스처 : GLuint의 배열[0..1] // 텍스처를 저장합니다.
PROcedure glGenTextures(n: GLsizei; Var 텍스처: GLuint);
OpenGL32;
절차 glBindTexture(대상: GLenum; 텍스처: GLuint);
OpenGL32;
{
바로 위의 코드는 텍스처를 로드하는 데 사용하는 코드입니다.
이 코드에 대해서는 자세히 설명하지 않겠습니다.
이는 6단원, 7단원, 8단원에서 사용한 코드와 정확히 같습니다.
이번에 로드한 비트맵은 star.bmp 입니다.
여기서는 glGenTextures(1, &texture[0])를 사용합니다.
텍스처를 생성합니다. 텍스처는 선형 필터링을 사용합니다.
}
Function LoadTexture: boolean; //비트맵을 로드하고 텍스처로 변환합니다.
바르
상태 : 부울; // 상태 표시기
TextureImage : Array[0..1] Of PTAUX_RGBImageRec // 텍스처 저장 공간 생성;
시작하다
상태 := 거짓;
ZeroMemory(@TextureImage, sizeof(TextureImage)); // 포인터를 NULL로 설정합니다.
TextureImage[0] := LoadBMP('Star.bmp');
TextureImage[0] <> Nil이면
시작하다
상태 := TRUE; // 상태를 TRUE로 설정합니다.
glGenTextures(1, 텍스처[0]); // 텍스처 생성
// 가장 가까운 필터 맵 생성
glBindTexture(GL_TEXTURE_2D, 텍스처[0]);
// 텍스처 생성
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST) // (신규)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST) // (신규)
glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureImage[0].sizeX,
텍스처이미지[0].sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE,
텍스처이미지[0].data);
끝;
If Assigned(TextureImage[0]) Then // 텍스처가 존재하는지 여부
If Assigned(TextureImage[0].data) Then // 텍스처 이미지가 존재하는지 여부
TextureImage[0].data := Nil; // 텍스처 이미지가 차지하는 메모리를 해제합니다.
TextureImage[0] := Nil; // 이미지 구조 해제
결과 := 상태; // 상태 반환
끝;
{glInit()에서 OpenGL 렌더링 모드를 설정합니다. 여기서는 심도 테스트를 사용하지 않을 것입니다.
1강의 코드를 사용하면,
glDepthFunc(GL_LEQUAL) 및 glEnable(GL_DEPTH_TEST)이 제거되었는지 확인하세요.
그렇지 않으면 결과가 엉망이 될 것입니다.
여기서는 텍스처 매핑을 사용합니다.
따라서 첫 번째 강의에 포함되지 않은 코드를 추가했는지 확인하세요.
색상을 혼합하여 텍스처 매핑을 활성화했음을 알 수 있습니다.
}
절차 glInit();
시작하다
If (LoadTexture 아님) Then // 텍스처 로딩 서브루틴 호출(신규)
exit; // 로드에 실패하면 종료합니다(신규).
glEnable(GL_TEXTURE_2D); // 텍스처 매핑 활성화
glShadeModel(GL_SMOOTH); // 그림자 다듬기 활성화
glClearColor(0.0, 0.0, 0.0, 0.5) // 검정색 배경
glClearDepth(1.0); //깊이 버퍼 설정
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // 정말 정밀한 원근 교정
glBlendFunc(GL_SRC_ALPHA, GL_ONE); // 반투명 효과를 얻기 위해 색상 혼합 기능을 설정합니다.
glEnable(GL_BLEND); // 색상 혼합 활성화
{다음은 새로운 코드입니다.
각 별의 시작 각도, 거리, 색상이 설정됩니다.
구조의 속성을 수정하는 것이 얼마나 쉬운지 알게 될 것입니다.
50개의 별이 모두 순환됩니다.
star[1]의 각도를 변경하려면 star[1].angle=a 특정 값만 하면 됩니다.
그것은 매우 간단합니다! }
For 루프 := 0 To 49 Do // 모든 별표를 설정하는 루프를 만듭니다.
시작하다
star[loop].angle := 0.0; // 모든 별은 0 각도에서 시작합니다.
{중심에서 루프번째 별까지의 거리를 루프의 값으로 나누어 전체 별 개수로 나눈 후 5.0을 곱합니다.
기본적으로 이것은 후자의 별을 이전 별보다 중심에서 조금 더 멀리 만듭니다.
이런 식으로 loop가 50(마지막 별)일 때 loop를 num으로 나눈 값은 정확히 1.0입니다.
5.0을 곱해야 하는 이유는 1.0*5.0이 5.0이기 때문입니다.
『CKER: 말도 안돼, 말도 안돼! 이 외국인은 왜 공이지처럼 생겼나요! :)'
5.0은 이미 화면 가장자리에 매우 가깝습니다. 별이 화면 밖으로 날아가는 것을 원하지 않으므로 5.0이 최선의 선택입니다.
물론 화면 속으로 장면을 더 깊게 설정하면,
5.0보다 큰 값을 사용할 수도 있지만 별은 더 작게 보일 것입니다(모두 원근감 때문입니다).
또한 각 별의 색상은 0에서 255 사이의 임의의 숫자라는 것을 알 수 있습니다.
여기의 색상 값 범위가 OpenGL의 일반적인 범위인 0.0~1.0이 아닌 이유가 궁금할 수 있습니다.
여기서 사용하는 색상 설정 기능은 이전 glColor4f 대신 glColor4ub입니다.
ub는 매개변수가 부호 없는 바이트 유형임을 의미합니다.
바이트의 값 범위는 0~255입니다.
부동 소수점 난수를 얻는 것보다 바이트 값을 사용하여 임의의 정수를 얻는 것이 더 쉬운 것 같습니다.
}
star[loop].dist := (Trunc(loop) / 50) * 5.0; // 중심으로부터 별까지의 거리를 계산합니다.
star[loop].r := random(256); // star[loop]에 대한 임의의 빨간색 구성요소를 설정합니다.
star[loop].g := random(256); // star[loop]에 대한 임의의 빨간색 구성요소를 설정합니다.
star[loop].b := random(256); // star[loop]에 대한 임의의 빨간색 구성요소를 설정합니다.
끝;
끝;
{
이제 glDraw() 그리기 코드를 살펴보겠습니다.
Lesson 1의 코드를 사용하는 경우 기존 DrawGLScene 코드를 삭제하고 아래 코드를 복사하면 됩니다.
실제로 첫 번째 강의의 코드에는 두 줄만 있으므로 잘라낼 내용이 많지 않습니다.
}
절차 glDraw();
시작하다
glClear(GL_COLOR_BUFFER_BIT Or GL_DEPTH_BUFFER_BIT); // 화면과 깊이 버퍼를 지웁니다.
glBindTexture(GL_TEXTURE_2D, 텍스처[0]) //텍스처 선택
For 루프 := 0 To 49 Do // 모든 별표를 설정하는 루프
시작하다
glLoadIdentity(); // 각 별을 그리기 전에 모델 관측 행렬을 재설정합니다.
glTranslatef(0.0, 0.0, Zoom); // 화면 더 깊이 이동('zoom' 값 사용)
glRotatef(tilt, 1.0, 0.0, 0.0); // 기울기 보기 각도('tilt' 값 사용)
{
이제 별을 움직여 보겠습니다.
별은 화면 중앙에서 시작됩니다.
가장 먼저 해야 할 일은 Y축을 따라 장면을 회전시키는 것입니다.
90도 회전하면 X축은 더 이상 왼쪽에서 오른쪽이 아니고 화면 안쪽에서 바깥쪽으로 나갑니다.
더 명확하게 하기 위해 예를 들어보겠습니다. 당신이 집 한가운데에 서 있다고 상상해보십시오.
이제 왼쪽 벽에 -x라고 적혀 있고, 앞에 있는 벽에 -z라고 적혀 있다고 상상해 보세요.
오른쪽 벽은 +x이고 뒤에 있는 벽은 +z입니다.
집 전체가 오른쪽으로 90도 회전했지만 움직이지 않으면 앞의 벽은 -z 대신 -x가 됩니다.
다른 모든 벽도 움직입니다. -z는 오른쪽에 나타나고 +z는 왼쪽에 나타나고 +x는 뒤에 나타납니다.
정신이 나갔나요? 장면을 회전하여 x 및 z 평면의 방향을 변경합니다.
두 번째 코드 줄은 x축을 따라 양수 값을 이동합니다.
일반적으로 x축의 양수 값은 화면 오른쪽(즉, x축의 일반적인 양수 방향)으로 이동한다는 의미입니다.
그러나 여기서는 y축을 중심으로 좌표계를 회전하므로 x축의 양의 방향은 어느 방향이든 가능합니다.
180도 회전하면 화면의 왼쪽과 오른쪽이 미러링됩니다.
따라서 양의 x축을 따라 이동할 때 왼쪽, 오른쪽, 앞으로 또는 뒤로 이동할 수 있습니다.
}
glRotatef(star[loop].angle, 0.0, 1.0, 0.0); //현재 그려진 별의 각도로 회전
glTranslatef(star[loop].dist, 0.0, 0.0); // X축을 따라 앞으로 이동합니다.
{
다음 코드에는 약간의 트릭이 있습니다.
별은 실제로 평평한 질감입니다.
이제 화면 중앙에 평평한 쿼드를 그리고 텍스처를 적용하면 보기 좋아집니다.
모든 것이 당신이 상상한 대로입니다. 하지만 y축을 따라 90도 회전하면
화면에서 사용자를 향한 텍스처의 유일한 두 면은 오른쪽과 왼쪽입니다. 그냥 얇은 선처럼 보입니다.
이것은 우리가 원하는 것이 아닙니다. 우리는 화면이 어떻게 회전하거나 기울어지더라도 별이 항상 우리를 바라보기를 원합니다.
별을 그리기 전에 별에 대한 모든 회전을 취소하여 이를 수행합니다.
회전을 반대로 하여 회전에 대응할 수 있습니다. 화면을 기울이면 별이 실제로 현재 각도로 회전합니다.
순서를 반대로 함으로써 현재 각도에서 별을 "회전 방지"합니다. 즉, 별은 현재 각도의 음수 값만큼 회전합니다.
즉,
별을 10도 회전하면 별이 해당 축에서 다시 화면을 향하도록 -10도 회전합니다.
아래 첫 번째 줄은 y축을 따른 회전을 취소합니다. 그런 다음 x축을 따라 화면 기울기를 오프셋해야 합니다.
이렇게 하려면 화면을 다시 회전(기울이기)하면 됩니다.
x축과 y축의 회전을 취소한 후 이제 별은 다시 완전히 우리를 향하고 있습니다.
}
glRotatef(-star[loop].angle, 0.0, 1.0, 0.0); // 현재 별의 각도 취소
glRotatef(-tilt, 1.0, 0.0, 0.0); // 화면 기울기 취소
{twinkle이 TRUE이면 먼저 화면에 회전하지 않은 별을 그립니다.
총 별 수(num)에서 현재 별 수(loop)를 뺀 후 1을 뺍니다.
각 별의 다양한 색상을 추출합니다(루프 범위가 0에서 num-1이기 때문에 수행됩니다).
예를 들어 결과가 10이면 10번 별의 색상을 사용합니다.
이렇게 하면 인접한 별의 색상이 항상 다릅니다. 좋은 생각은 아니지만 효과가 있습니다.
마지막 값은 알파 채널 구성 요소입니다. 값이 작을수록 별은 더 어두워집니다.
반짝임이 활성화되어 있으므로 각 별은 두 번 그려지게 됩니다.
컴퓨터 성능에 따라 프로그램 실행 속도가 느려집니다.
하지만 두 번의 패스로 그린 별들의 색깔은 서로 섞여서 큰 효과를 낸다.
동시에 첫 번째 패스의 별은 회전하지 않았기 때문에 반짝임을 활성화한 후의 별은 애니메이션 효과처럼 보입니다.
(이것이 이해가 되지 않는다면 직접 가서 프로그램의 실행 효과를 확인해 보세요.)
텍스처를 색칠하는 것이 쉽다는 점은 주목할 가치가 있습니다.
텍스처 자체는 흑백이지만 페인팅하기 전에 선택한 색상으로 텍스처가 변경됩니다.
또한 여기서 사용하는 색상 값이 바이트 유형이라는 점도 주목할 가치가 있습니다.
일반적인 부동 소수점 숫자 대신. 알파 채널 구성 요소도 이와 같습니다. }
If (반짝임) Then // 반짝임 효과 활성화
시작하다
// 바이트 값을 사용하여 색상 지정
glColor4ub(스타[(50 - 루프) - 1].r, 스타[(50 - 루프) - 1].g,
star[(50 - 루프) - 1].b, 255);
glBegin(GL_QUADS); // 텍스처 매핑된 쿼드 그리기 시작
glTexCoord2f(0.0, 0.0);
glVertex3f(-1.0, -1.0, 0.0);
glTexCoord2f(1.0, 0.0);
glVertex3f(1.0, -1.0, 0.0);
glTexCoord2f(1.0, 1.0);
glVertex3f(1.0, 1.0, 0.0);
glTexCoord2f(0.0, 1.0);
glVertex3f(-1.0, 1.0, 0.0);
glEnd(); // 사각형 그리기 끝
끝;
{
이제 별의 두 번째 패스를 그립니다.
이전 코드와 유일한 차이점은 이번에는 별이 반드시 그려지고 이번에는 별이 z축을 중심으로 회전한다는 것입니다.
}
glRotatef(spin, 0.0, 0.0, 1.0); // z축을 중심으로 별을 회전시킵니다.
// 바이트 값을 사용하여 색상 지정
glColor4ub(스타[루프].r, 스타[루프].g, 스타[루프].b, 255);
glBegin(GL_QUADS); // 텍스처 매핑된 쿼드 그리기 시작
glTexCoord2f(0.0, 0.0);
glVertex3f(-1.0, -1.0, 0.0);
glTexCoord2f(1.0, 0.0);
glVertex3f(1.0, -1.0, 0.0);
glTexCoord2f(1.0, 1.0);
glVertex3f(1.0, 1.0, 0.0);
glTexCoord2f(0.0, 1.0);
glVertex3f(-1.0, 1.0, 0.0);
glEnd(); // 사각형 그리기 끝
{아래 코드는 별의 움직임을 나타냅니다.
모든 별을 회전시키기 위해 스핀 값을 높입니다(회전).
그런 다음 각 별의 회전 각도를 loop/num만큼 늘립니다.
이로 인해 중심에서 멀리 있는 별이 더 빠르게 회전하게 됩니다. 마지막으로 화면 중앙에서 각 별의 거리를 줄입니다.
마치 별들이 화면 중앙으로 끊임없이 빨려들어가는 것처럼 보입니다. }
spin := spin + 0.01; // 별의 회전
star[loop].angle := star[loop].angle + Trunc(loop) / 50 // 별의 회전 각도를 변경합니다.
star[loop].dist := star[loop].dist - 0.01; // 중심으로부터 별의 거리를 변경합니다.
{다음 몇 줄은 별이 화면 중앙에 닿았는지 확인합니다.
별이 화면 중앙에 닿으면 새로운 색상을 부여하고 바깥쪽으로 5단위 이동합니다.
별은 화면 중앙으로 돌아가는 여행을 시작합니다. }
If (star[loop].dist < 0.0) Then // 별이 중심에 도달했나요?
시작하다
star[loop].dist := star[loop].dist + 5.0; // 바깥쪽으로 5단위 이동;
star[loop].r := random(256); // 새로운 빨간색 구성요소 할당
star[loop].g := random(256); // 새로운 녹색 구성요소 할당
star[loop].b := random(256); // 새로운 파란색 구성요소 할당
끝;
끝;
끝;
{
이제 키보드를 모니터링하는 코드를 추가합니다.
WinMain()으로 아래로 이동합니다. SwapBuffers(hDC) 라인을 찾으세요.
이 줄 뒤에 키보드 모니터링 코드를 추가하겠습니다.
코드는 T 키를 눌렀는지 확인합니다.
T 키를 눌렀다가 떼면 if 블록의 코드가 실행됩니다.
Twinkle이 FALSE이면 TRUE가 됩니다.
그 반대. T 키를 누르고 있는 동안 tp는 TRUE가 됩니다.
이렇게 하면 T 키를 계속 누르고 있으면 블록 내의 코드가 반복적으로 실행되는 것을 방지할 수 있습니다.
}
If (keys[ord('T')] And Not tp) Then // T 키를 눌렀고 tp 값이 FALSE인지 여부
시작하다
tp := TRUE; // 그렇다면 tp를 TRUE로 설정합니다.
Twinkle := 반짝임 아님; // 반짝임 값을 뒤집습니다.
끝;
{
아래 코드는 T 키가 해제되었는지 확인합니다.
그렇다면 tp=FALSE를 설정하세요.
tp 값이 FALSE가 아닌 한,
그렇지 않으면 T 키를 누르고 있는 동안 아무 일도 일어나지 않습니다. 따라서 이 코드 줄은 중요합니다.
}
If (키가 아님[Ord('T')]) Then // T 키를 놓았습니까?
시작하다
tp := FALSE; // 그렇다면 tp는 FALSE입니다.
끝;
{나머지 코드는 위쪽 및 아래쪽 화살표 키, 페이지 업 키 또는 페이지 다운 키가 눌렸는지 확인합니다. }
If (keys[VK_UP]) Then // 위쪽 화살표 키를 눌렀습니까?
기울기 := 기울기 - 0.5; // 화면을 위쪽으로 기울입니다.
If (keys[VK_DOWN]) Then // 아래쪽 화살표 키가 눌렸습니까?
기울기 := 기울기 + 0.5; // 화면을 아래쪽으로 기울입니다.
If (keys[VK_PRIOR]) Then // 페이지 업 키가 눌렸습니까?
줌 := 줌 - 0.2 // 축소
If (keys[VK_NEXT]) Then // 페이지 다운 키가 눌렸습니까?
Zoom := 줌 + 0.2; // 확대
{
이번 강의에서는 그레이스케일 비트맵 텍스처를 로드하는 방법을 최선을 다해 설명하겠습니다.
배경색을 제거한 후(혼합 색상 사용) 다시 색상을 지정하고 마지막으로 3D 장면에서 움직이게 만듭니다.
아름다운 색상과 애니메이션 효과를 만드는 방법을 보여드렸습니다.
구현 원칙은 원본 비트맵에 비트맵 복사본을 겹치는 것입니다.
지금까지 내가 너희에게 가르친 모든 것을 너희가 잘 이해하기만 하면
아무 문제 없이 자신만의 3D 데모를 만들 수 있어야 합니다.
기본적인 내용은 모두 다뤘습니다! }
//========마이링:
//1~9강은 NEHE님 말씀대로 기본 지식은 기본적으로 설명하였습니다.
//다음 튜토리얼을 봤는데, 다른 분들이 쓴 것 같더라고요. 좋은 예시가 있으면 선별해서 따라하겠습니다.
//리뉴얼 피곤해요 푹 쉬세요 :) 다음에 또 만나요