{
이번 강의에서는 세 가지 다른 텍스처 필터링 방법을 사용하는 방법을 가르쳐 드리겠습니다.
키보드를 사용하여 장면에서 개체를 이동하는 방법을 가르치고 OpenGL 장면에서 간단한 조명을 적용하는 방법도 알려줍니다.
이 강의에는 많은 내용이 포함되어 있습니다. 이전 강의에 대해 궁금한 점이 있으면 먼저 돌아가서 검토하세요.
그 뒤에 있는 코드를 살펴보기 전에 기본 사항을 잘 이해하는 것이 중요합니다.
우리는 여전히 첫 번째 강의의 코드를 수정합니다.
이전과 다른 점은 큰 변화가 있을 때마다 전체 코드를 작성한다는 점이다.
먼저 SysUtils 유닛과 Glaux 유닛을 추가해야 합니다.
}
용도
SysUtils,
오픈글,
창문,
메시지,
글라우스 '../../GLAUX/Glaux.pas';
//다음 줄은 새 변수를 추가합니다.
//3개의 부울 변수를 추가합니다.
// light 변수는 조명이 켜져 있는지 추적합니다.
//변수 lp 및 fp는 'L' 및 'F' 키가 눌렸는지 저장하는 데 사용됩니다.
//이 변수의 중요성에 대해서는 나중에 설명하겠습니다. 지금은 그것을 제쳐두십시오.
light : 부울; // 광원 켜기/끄기
lp : Boolean; // L 키가 눌렸나요?
fp : Boolean; // F 키가 눌렸나요?
//이제 x축과 y축을 중심으로 한 회전 각도의 단계 크기를 제어하는 5개의 변수를 설정합니다.
//x축과 y축을 중심으로 한 회전 속도입니다.
//또한 화면 깊이까지의 거리를 제어하기 위해 z 변수가 생성됩니다.
xrot : GLfloat; // X 회전
yrot : GLfloat; // Y 회전
xspeed : GLfloat; // X 회전 속도
yspeed : GLfloat; // Y 회전 속도
z : GLfloat = -5.0 f; // 화면 깊은 곳까지의 거리
//그런 다음 광원을 생성하는 데 사용되는 배열을 설정합니다.
//우리는 두 개의 다른 조명을 사용할 것입니다.
//첫 번째는 주변광이라고 합니다. 주변광은 모든 방향에서 나옵니다.
//장면의 모든 객체는 주변광에 의해 조명됩니다.
//두 번째 유형의 광원을 확산광이라고 합니다.
//확산광은 특정 광원에 의해 생성되며 장면의 객체 표면에 반사를 생성합니다.
//확산광에 의해 직접적으로 조명된 물체 표면은 매우 밝아집니다.
//빛이 거의 닿지 않는 부분이 더 어둡게 보입니다.
//이것은 우리가 만든 나무 상자의 가장자리에 매우 좋은 그림자 효과를 생성합니다.
//광원을 만드는 과정은 색상을 만드는 과정과 똑같습니다.
//처음 세 개의 매개변수는 RGB 3색 구성요소이고 마지막 매개변수는 알파 채널 매개변수입니다.
//따라서 다음 코드에서는 절반 정도 밝은(0.5f) 흰색 주변광을 얻습니다.
//주변광이 없으면 확산광이 닿지 않는 영역은 매우 어두워집니다.
LightAmbient: Array[0..3] Of GLfloat = (0.5, 0.5, 0.5, 1.0) //주변광 매개변수(신규)
//다음 코드 줄에서는 가장 밝은 확산광을 생성합니다.
//모든 매개변수 값은 최대값인 1.0f로 가져옵니다.
//나무 상자 앞부분이 빛나서 보기 좋게 보일 것입니다.
LightDiffuse: Array[0..3] Of GLfloat = (1.0, 1.0, 1.0, 1.0) // 확산 조명 매개변수(신규)
//마지막으로 광원의 위치를 저장합니다.
//처음 세 개의 매개변수는 glTranslate와 동일합니다.
//XYZ 축의 변위는 각각입니다.
//빛이 나무 상자 전면을 직접 비추기를 원하므로 XY 축의 변위는 모두 0.0입니다.
//세 번째 값은 Z축의 변위입니다.
//빛이 항상 나무 상자 앞에 있도록 하기 위해,
//그래서 광원을 화면에서 관찰자(당신) 쪽으로 이동합니다.
//보통 화면의 위치, 즉 모니터의 스크린 유리를 Z축 0.0점이라고 부릅니다.
//그래서 Z축의 변위는 최종적으로 2.0으로 설정됩니다.
//광원이 보이면 모니터 앞에 떠 있는 것입니다.
//물론 모니터 화면 유리 뒤에 있지 않으면 상자를 볼 수 없습니다.
// 『번역자 주: NeHe의 인내심에 감사드립니다.
//솔직히 가끔 짜증날 때도 있어요. 왜 이렇게 간단한 것에 대해 말도 안 되는 소리를 하는 걸까요?
//하지만 모든 것이 명확하다면 아직도 이렇게 페이지를 넘기며 끝없이 읽을 것입니까? 』
//마지막 매개변수는 1.0f로 사용됩니다.
//여기에 지정된 좌표가 광원의 위치임을 OpenGL에 알려줍니다. 향후 튜토리얼에서 더 자세히 설명하겠습니다.
LightPosition: Array[0..3] Of GLfloat = (0.0, 0.0, 2.0, 1.0) // 광원 위치(신규)
//필터 변수는 표시할 때 사용된 텍스처 유형을 추적합니다.
//첫 번째 텍스처(텍스처 0)는 gl_nearest(부드럽지 않은) 필터링 방법을 사용하여 구성됩니다.
//두 번째 텍스처(텍스처 1)는 gl_linear(선형 필터링) 방법을 사용합니다.
//화면에 가까운 이미지가 더 부드러워 보입니다.
//세 번째 텍스처(텍스처 2)는 밉맵 필터링 방법을 사용합니다.
//이렇게 하면 매우 보기 좋은 텍스처가 생성됩니다.
//사용 유형에 따라 필터 변수의 값은 각각 0, 1 또는 2와 같습니다.
//첫 번째 텍스처부터 시작하겠습니다.
//텍스처는 세 가지 다른 텍스처에 대한 저장 공간을 할당합니다.
//각각 텍스처[0], 텍스처[1], 텍스처[2]에 있습니다.
filter : GLuint; // 필터 유형
텍스처 : GLuint의 배열[0..2] // 텍스처 3개를 위한 저장 공간
PRocedure glGenTextures(n: GLsizei; Var 텍스처: GLuint);
OpenGL32;
절차 glBindTexture(대상: GLenum; 텍스처: GLuint);
OpenGL32;
함수 gluBuild2DMipmaps(대상: GLenum; 구성 요소, 너비, 높이: GLint;
형식, atype: GLenum; 데이터: 포인터): 외부 glu32 이름;
'gluBuild2DMipmaps';
{
이제 비트맵을 로드하고 이를 사용하여 세 가지 다른 텍스처를 만듭니다.
이 단원에서는 glaux 보조 라이브러리를 사용하여 비트맵을 로드합니다.
따라서 컴파일 시 glaux 라이브러리가 포함되어 있는지 확인해야 합니다.
Delphi와 VC++에는 모두 glaux 라이브러리가 포함되어 있는 것으로 알고 있지만 다른 언어에서는 이를 보장하지 않습니다.
"역자 주: glaux는 OpenGL 보조 라이브러리입니다. OpenGL의 크로스 플랫폼 특성에 따르면,
코드는 모든 플랫폼에서 공통되어야 합니다. 그러나 보조 라이브러리는 공식 OpenGL 표준 라이브러리가 아닙니다.
모든 플랫폼에서 사용할 수는 없습니다. 그러나 Win32 플랫폼에서는 사용할 수 있습니다.
하하, 물론 BCB도 문제 없습니다. 』여기에서는 새로 추가된 코드에만 주석을 달았습니다.
특정 코드 줄에 대해 질문이 있는 경우 튜토리얼 6을 확인하세요.
이 강의에서는 텍스처 로드 및 생성에 대해 매우 자세히 설명합니다.
이전 코드 조각 뒤와 glResizeWnd() 앞,
다음 코드를 추가했습니다. 이는 6강에서 비트맵을 로드하는 데 사용된 코드와 거의 동일합니다.
}
함수 LoadBmp(파일명: pchar): PTAUX_RGBImageRec;
바르
BitmapFile : // 파일 핸들;
시작하다
If Filename = '' Then // 파일 이름이 제공되었는지 확인합니다.
result := Nil; // 제공되지 않은 경우 NULL을 반환합니다.
BitmapFile := FileOpen(Filename, fmOpenWrite) //파일 열기를 시도합니다.
If BitmapFile > 0 Then // 파일이 존재합니까?
시작하다
FileClose(BitmapFile) //핸들 닫기
result := auxDIBImageLoadA(filename); //비트맵을 로드하고 포인터를 반환합니다.
끝
또 다른
result := Nil; // 로딩에 실패하면 NiL을 반환합니다.
끝;
Function LoadTexture: boolean; //비트맵을 로드하고 텍스처로 변환합니다.
바르
상태 : 부울; // 상태 표시기
TextureImage : Array[0..1] Of PTAUX_RGBImageRec // 텍스처 저장 공간 생성;
시작하다
상태 := 거짓;
ZeroMemory(@TextureImage, sizeof(TextureImage)); // 포인터를 NULL로 설정합니다.
TextureImage[0] := LoadBMP('Walls.bmp');
TextureImage[0] <> Nil이면
시작하다
상태 := TRUE; // 상태를 TRUE로 설정합니다.
glGenTextures(1, 텍스처[0]); // 텍스처 생성
//제 6강에서는 선형 필터링된 텍스처 매핑을 사용했습니다.
//이것은 머신의 처리 능력이 상당히 많이 필요하지만 꽤 좋아 보입니다.
//이 단원에서 생성할 첫 번째 텍스처는 GL_NEAREST 메서드를 사용합니다.
//원칙적으로 이 메서드는 실제로 필터링을 수행하지 않습니다.
//처리 능력을 거의 차지하지 않으며 성능도 좋지 않습니다.
//유일한 장점은 우리 프로젝트가 빠른 시스템과 느린 시스템 모두에서 정상적으로 실행될 수 있다는 것입니다.
//MIN과 MAG 모두에 GL_NEAREST를 사용한다는 것을 알 수 있습니다.
//GL_NEAREST와 GL_LINEAR을 혼합할 수 있습니다.
//텍스처가 더 좋아 보이지만 속도가 더 중요하므로 품질이 낮은 맵을 모두 사용합니다.
//MIN_FILTER는 텍스처의 원래 크기보다 작게 이미지를 그릴 때 사용됩니다.
//MAG_FILTER는 텍스처의 원래 크기보다 크게 이미지를 그릴 때 사용됩니다.
// 가장 가까운 필터 맵 생성
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);
//다음 텍스처는 6강의 선형 필터링과 동일합니다. 유일한 차이점은 이번에 배치되었다는 것입니다.
//텍스처[1]. 이것이 두 번째 텍스처이기 때문입니다. 배치된 경우
//texture[0], 이전에 생성된 GL_NEAREST 텍스처를 덮어씁니다.
glBindTexture(GL_TEXTURE_2D, text[1]); //비트맵 데이터에서 생성된 일반적인 텍스처 사용
// 텍스처 생성
glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureImage[0].sizeX,
텍스처이미지[0].sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE,
텍스처이미지[0].data);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR) // 선형 필터링
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR) // 선형 필터링
//다음은 텍스처를 생성하는 새로운 방법입니다. 밉매핑!
// 『번역자 주: 이 단어를 중국어로 번역할 수는 없지만 상관없습니다. 이 단락을 읽고 나면 그 의미가 가장 중요하다는 것을 알게 될 것입니다. 』
//화면에서 이미지가 매우 작아지면 많은 세부 정보가 손실되는 것을 알 수 있습니다.
//지금은 좋아 보이던 패턴이 보기 흉해졌습니다. OpenGL에게 밉맵 텍스처를 생성하라고 지시하면,
//OpenGL은 다양한 크기의 고품질 텍스처를 생성하려고 시도합니다. 밉맵 텍스처를 화면에 그릴 때,
//OpenGL은 그리기 위해 생성한 가장 보기 좋은 텍스처(자세한 내용 포함)를 선택합니다.
//원본 이미지의 크기를 조정하는 대신(세부 사항이 손실됨)
//OpenGL이 텍스처 너비와 높이에 적용하는 제한(64, 128, 256 등)을 해결할 수 있는 방법이 있다고 말한 적이 있습니다.
//해결책은 gluBuild2DMipmaps입니다. 내가 찾은 것에서 임의의 비트맵을 사용하여 텍스처를 만들 수 있습니다.
//OpenGL은 자동으로 일반 크기로 크기를 조정합니다.
//세 번째 텍스처이므로 텍스처[2]에 저장합니다. 이런 식으로 이 단원의 세 가지 텍스처가 모두 생성되었습니다.
//MipMapped 텍스처 생성
glBindTexture(GL_TEXTURE_2D, 텍스처[2]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
GL_LINEAR_MIPMAP_NEAREST) // (신규)
//다음 줄은 밉맵 텍스처를 생성합니다.
//3가지 색상(빨간색, 녹색, 파란색)을 사용하여 2D 텍스처를 생성합니다.
//TextureImage[0].sizeX는 비트맵 너비입니다.
//TextureImage[0].sizeY는 비트맵 높이입니다.
//(====어떤 이유로 Delphi에서 이 함수에는 높이 매개변수가 없습니다.
//하지만 도움말에는 있습니다. 델파이가 더 이상 무엇을 할 지 모르기 때문에 우울해집니다.
//마지막으로 이전에 gluBuild2DMipmaps를 직접 작성했습니다.
//glu32.dll에서 gluBuild2DMipmaps 함수를 로드하려면 =====)
//GL_RGB는 RGB 색상을 차례로 사용한다는 의미입니다.
//GL_UNSIGNED_BYTE는 텍스처 데이터의 단위가 바이트임을 의미합니다.
//TextureImage[0].data는 텍스처를 생성하는 데 사용하는 비트맵을 가리킵니다.
gluBuild2DMipmaps(GL_TEXTURE_2D, 3, TextureImage[0].sizeX,
텍스처이미지[0].sizey, GL_RGB, GL_UNSIGNED_BYTE,
TextureImage[0].data) //(신규) }
끝;
If Assigned(TextureImage[0]) Then // 텍스처가 존재하는지 여부
If Assigned(TextureImage[0].data) Then // 텍스처 이미지가 존재하는지 여부
TextureImage[0].data := Nil; // 텍스처 이미지가 차지하는 메모리를 해제합니다.
TextureImage[0] := Nil; // 이미지 구조 해제
결과 := 상태; // 상태 반환
끝;
//그런 다음 텍스처를 로드하고 OpenGL 설정을 초기화할 차례입니다.
//GLInit 함수의 첫 번째 줄은 위 코드를 사용하여 텍스처를 로드합니다.
//텍스처를 생성한 후 glEnable(GL_TEXTURE_2D)을 호출하여 2D 텍스처 매핑을 활성화합니다.
//그림자 모드는 부드러운 음영(Smooth Shading)으로 설정됩니다.
//배경색을 검정색으로 설정하고 깊이 테스트를 활성화한 다음 최적화된 원근 계산을 활성화합니다.
Procedure glInit(); // 여기서 OpenGL에 대한 모든 설정을 시작합니다.
시작하다
If (LoadTexture 아님) Then // 텍스처 로딩 서브루틴을 호출합니다.
exit; // 로드에 실패하면 종료합니다.
glEnable(GL_TEXTURE_2D); // 텍스처 매핑 활성화
glShadeModel(GL_SMOOTH); // 그림자 다듬기 활성화
glClearColor(0.0, 0.0, 0.0, 0.0) // 검정색 배경
glClearDepth(1.0); //깊이 버퍼 설정
glEnable(GL_DEPTH_TEST); // 깊이 테스트 활성화
glDepthFunc(GL_LESS); // 완료된 깊이 테스트 유형
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); //매우 최적화된 원근 투영 계산
//이제 광원 설정을 시작합니다. 아래의 다음 줄은 방출되는 주변광의 양을 설정합니다.
//광원 light1이 빛을 내기 시작합니다.
//이 단원을 시작할 때 LightAmbient 배열에 주변광의 양을 저장합니다.
//이제 이 배열(밝기가 절반인 주변광)을 사용하겠습니다.
glLightfv(GL_LIGHT1, GL_AMBIENT, @LightAmbient[0]) // 주변광 설정
//다음으로 확산광의 양을 설정합니다. 이는 LightDiffuse 배열(최대 밝기 백색광)에 저장됩니다.
glLightfv(GL_LIGHT1, GL_DIFFUSE, @LightDiffuse[0]) // 확산광 설정
//광원의 위치를 설정합니다.
//위치는 LightPosition 배열에 저장됩니다.
//(정확히 나무 상자 전면 중앙에 위치, X-0.0, Y-0.0, <화면 밖> Z 방향으로 관찰자를 향해 2단위 이동).
glLightfv(GL_LIGHT1, GL_POSITION, @LightPosition); // 광원 위치
//마지막으로 광원 1번을 활성화합니다. 아직 GL_LIGHTING을 활성화하지 않았습니다.
//그래서 빛을 볼 수 없습니다.
//기억하세요: 광원을 설정하거나 배치하거나 활성화하는 것만으로는 작동하지 않습니다.
//GL_LIGHTING을 활성화하지 않는 한.
glEnable(GL_LIGHT1); // 1번 광원 활성화
끝;
//다음 코드 조각은 텍스처 큐브를 그립니다. 새 코드에만 주석을 달았습니다.
//주석이 없는 코드에 대해 질문이 있으면 6강으로 돌아가세요.
Procedure glDraw(); // 모든 그리기는 여기서부터 시작됩니다.
시작하다
glClear(GL_COLOR_BUFFER_BIT Or GL_DEPTH_BUFFER_BIT) // 화면 및 깊이 버퍼 지우기
glLoadIdentity(); //현재 모델 관찰 행렬을 재설정합니다.
//다음 세 줄의 코드는 텍스처 큐브를 배치하고 회전시킵니다.
//glTranslatef(0.0,0.0,z)는 Z 축을 따라 큐브 Z 단위를 이동합니다.
//glRotatef(xrot,1.0f,0.0f,0.0f)는 X축 xrot을 중심으로 큐브를 회전합니다.
//glRotatef(yrot,0.0f,1.0f,0.0f)는 Y축을 중심으로 큐브 yrot를 회전합니다.
glTranslatef(0.0, 0.0, z); // 화면 z 단위로 이동/해제
glRotatef(xrot, 1.0, 0.0, 0.0); // X축을 중심으로 회전
glRotatef(yrot, 0.0, 1.0, 0.0); // Y축을 중심으로 회전
//다음 줄은 6강에서 했던 것과 유사합니다.
//차이점은 이번에 바인딩한 텍스처가 텍스처[필터]라는 것입니다.
//이전 강의의 텍스처[0] 대신.
//F 키를 누를 때마다 필터 값이 증가합니다.
//이 값이 2보다 크면 필터 변수가 0으로 재설정됩니다.
//프로그램이 초기화되면 filter 변수의 값도 0으로 설정됩니다.
//변수 필터를 사용하여 세 가지 텍스처 중 하나를 선택할 수 있습니다.
glBindTexture(GL_TEXTURE_2D, text[filter]); //필터에 의해 결정된 텍스처를 선택합니다.
glBegin(GL_QUADS); // 사각형 그리기 시작
//glNormal3f는 이 단원의 새로운 내용입니다. 정상은 정상을 의미합니다.
//소위 법선은 표면(다각형)의 한 점을 통과하고 이 표면(다각형)에 수직인 직선을 나타냅니다.
//광원을 사용할 경우 법선을 지정해야 합니다. 법선은 OpenGL에게 다각형의 방향을 알려주고 다각형의 앞면과 뒷면을 나타냅니다.
//노멀을 지정하지 않으면 이상한 일이 발생할 수 있습니다. 조명을 받아서는 안되는 표면이 조명되고 다각형의 뒷면도 조명됩니다....
//그런데 법선은 다각형의 바깥쪽을 가리켜야 합니다. 상자의 전면을 보면 법선이 양의 Z축과 같은 방향임을 알 수 있습니다.
//이것은 법선이 관찰자, 즉 자신을 향하고 있음을 의미합니다. 이것이 바로 우리가 바라는 것입니다.
//나무 상자 뒷면의 경우 원하는 대로 법선이 보는 사람의 반대쪽을 향합니다.
//큐브가 X 또는 Y축을 따라 180도 회전하면 앞면의 법선은 여전히 관찰자를 향하고 있고 뒷면의 법선은 여전히 관찰자의 반대쪽을 향하고 있습니다.
//즉, 어떤 표면이든지 관찰자를 향하는 한 이 표면의 법선은 관찰자를 가리킵니다.
//광원이 관찰자에게 바로 인접해 있으므로 법선이 관찰자를 향할 때마다 이 표면이 조명됩니다.
//법선이 광원에 가까울수록 더 밝게 나타납니다.
//관측점을 큐브 내부에 배치하면 법선 내부가 어두워집니다.
//법선이 바깥쪽을 향하기 때문입니다. 큐브 내부에 광원이 없으면 당연히 칠흑같이 어두워질 것입니다.
// 앞쪽
glNormal3f(0.0, 0.0, 1.0); // 법선은 관찰자를 가리킵니다.
glTexCoord2f(0.0, 0.0);
glVertex3f(-1.0, -1.0, 1.0); // 쿼드의 텍스처 및 왼쪽 아래
glTexCoord2f(1.0, 0.0);
glVertex3f(1.0, -1.0, 1.0); // 쿼드의 텍스처 및 오른쪽 아래
glTexCoord2f(1.0, 1.0);
glVertex3f(1.0, 1.0, 1.0); //쿼드의 텍스처 및 오른쪽 위
glTexCoord2f(0.0, 1.0);
glVertex3f(-1.0, 1.0, 1.0); //쿼드의 텍스처 및 왼쪽 위
// 나중에
glNormal3f(0.0, 0.0, -1.0); // 일반 면은 보는 사람에게서 멀어집니다.
glTexCoord2f(1.0, 0.0);
glVertex3f(-1.0, -1.0, -1.0); // 쿼드의 텍스처 및 오른쪽 아래
glTexCoord2f(1.0, 1.0);
glVertex3f(-1.0, 1.0, -1.0); //쿼드의 텍스처 및 오른쪽 위
glTexCoord2f(0.0, 1.0);
glVertex3f(1.0, 1.0, -1.0); //쿼드의 텍스처 및 왼쪽 위
glTexCoord2f(0.0, 0.0);
glVertex3f(1.0, -1.0, -1.0); // 쿼드의 텍스처 및 왼쪽 아래
// 윗면
glNormal3f(0.0, 1.0, 0.0); // 법선 상향
glTexCoord2f(0.0, 1.0);
glVertex3f(-1.0, 1.0, -1.0); //쿼드의 텍스처 및 왼쪽 위
glTexCoord2f(0.0, 0.0);
glVertex3f(-1.0, 1.0, 1.0); // 쿼드의 텍스처 및 왼쪽 아래
glTexCoord2f(1.0, 0.0);
glVertex3f(1.0, 1.0, 1.0); // 쿼드의 텍스처 및 오른쪽 아래
glTexCoord2f(1.0, 1.0);
glVertex3f(1.0, 1.0, -1.0); //쿼드의 텍스처 및 오른쪽 위
// 맨 아래
glNormal3f(0.0, -1.0, 0.0); // 법선이 아래를 향함
glTexCoord2f(1.0, 1.0);
glVertex3f(-1.0, -1.0, -1.0); // 쿼드의 텍스처 및 오른쪽 위
glTexCoord2f(0.0, 1.0);
glVertex3f(1.0, -1.0, -1.0); //쿼드의 텍스처 및 왼쪽 위
glTexCoord2f(0.0, 0.0);
glVertex3f(1.0, -1.0, 1.0); // 쿼드의 텍스처 및 왼쪽 아래
glTexCoord2f(1.0, 0.0);
glVertex3f(-1.0, -1.0, 1.0); // 쿼드의 텍스처 및 오른쪽 아래
// 오른쪽
glNormal3f(1.0, 0.0, 0.0); // 오른쪽으로 법선
glTexCoord2f(1.0, 0.0);
glVertex3f(1.0, -1.0, -1.0); // 쿼드의 텍스처 및 오른쪽 아래
glTexCoord2f(1.0, 1.0);
glVertex3f(1.0, 1.0, -1.0); //쿼드의 텍스처 및 오른쪽 위
glTexCoord2f(0.0, 1.0);
glVertex3f(1.0, 1.0, 1.0); //쿼드의 텍스처 및 왼쪽 위
glTexCoord2f(0.0, 0.0);
glVertex3f(1.0, -1.0, 1.0); // 쿼드의 텍스처 및 왼쪽 아래
// 왼쪽
glNormal3f(-1.0, 0.0, 0.0); // 왼쪽으로 법선
glTexCoord2f(0.0, 0.0);
glVertex3f(-1.0, -1.0, -1.0); // 쿼드의 텍스처 및 왼쪽 아래
glTexCoord2f(1.0, 0.0);
glVertex3f(-1.0, -1.0, 1.0); // 쿼드의 텍스처 및 오른쪽 아래
glTexCoord2f(1.0, 1.0);
glVertex3f(-1.0, 1.0, 1.0); //쿼드의 텍스처 및 오른쪽 위
glTexCoord2f(0.0, 1.0);
glVertex3f(-1.0, 1.0, -1.0); //쿼드의 텍스처 및 왼쪽 위
glEnd();
xrot := xrot + xspeed; // xrot은 xspeed 단위를 증가시킵니다.
yrot := Yrot + yspeed; // yrot는 yspeed 단위를 증가시킵니다.
끝;
//이제 WinMain() 메인 함수로 이동합니다.
//여기에 제어 코드를 추가하여 광원을 켜고 끄고, 나무 상자를 회전하고, 필터링 방법을 전환하고, 나무 상자를 더 가깝고 멀리 이동합니다.
// WinMain() 함수의 끝 부분에 SwapBuffers(hDC) 코드 줄이 표시됩니다.
//이 줄 뒤에 다음 코드를 추가합니다.
//코드는 L 키가 눌렸는지 확인합니다.
//L 키를 눌렀으나 lp 값이 false가 아닌 경우 L 키를 떼지 않았음을 의미하므로 이때는 아무 일도 일어나지 않습니다.
SwapBuffers(h_DC); // 버퍼 교체(이중 버퍼)
If (keys[ord('L')] 그리고 lp가 아님) 그러면
시작하다
//lp 값이 false인 경우
//L 키를 아직 누르지 않았거나 눌렀음을 의미하며 lp는 TRUE로 설정됩니다.
//이 두 가지 조건을 동시에 확인하는 이유는 L 키가 눌리지 않도록 하기 위함입니다.
//이 코드는 반복적으로 실행되어 양식이 계속 깜박이게 합니다.
//lp가 true로 설정된 후 컴퓨터는 L 키를 눌렀음을 알게 됩니다.
//따라서 광원을 켜거나 끌 수 있습니다. 부울 변수 조명은 광원 켜기/끄기를 제어합니다.
lp := true; // lp가 TRUE로 설정됩니다.
light := 빛이 아님; // 광원을 TRUE/FALSE로 전환합니다.
If Not Light Then // 광원이 없는 경우
glDisable(GL_LIGHTING) //광원 비활성화
그 밖에 // 기타
glEnable(GL_LIGHTING); //광원 활성화
끝;
If Notkey[ord('L')] Then //L 키가 해제되었습니까?
lp := FALSE; // 그렇다면 lp를 FALSE로 설정합니다.
//그런 다음 "F" 키에 대해 비슷한 검사를 수행합니다.
//"F" 키를 눌렀는데 "F" 키를 누르지 않았거나 한 번도 누른 적이 없는 경우
//변수 fp를 true로 설정합니다. 이는 키가 눌려졌다는 의미입니다.
//그런 다음 필터 변수에 하나를 추가합니다. 필터 변수가 2보다 큰 경우
//(여기서 사용하는 배열은 텍스처[3]이므로 2보다 큰 텍스처는 존재하지 않습니다.),
//필터 변수를 0으로 재설정합니다.
If (keys[ord('F')] And Not fp) Then // F 키가 눌렸습니까?
시작하다
fp := TRUE; // fp가 TRUE로 설정됩니다.
inc(filter); // 필터 값에 1을 더합니다.
필터 > 2이면 // 2보다 큰가?
filter := 0; // 0으로 재설정되는 경우
끝;
If Notkey[ord('F')] Then //F 키를 놓았습니까?
fp := FALSE; // fp가 FALSE로 설정된 경우
//이 네 줄은 PageUp 키가 눌렸는지 확인합니다. 그렇다면 z 변수의 값을 줄이십시오. 이런 식으로 DrawGLScene 함수에 포함된 glTranslatef(0.0f,0.0f,z) 호출은 나무 상자를 뷰어로부터 더 멀리 이동시킵니다.
키[VK_PRIOR]이면 //PageUp을 눌렀습니까?
z := z - 0.02; // 누르면 나무 상자를 화면 안쪽으로 이동합니다.
//다음 네 줄에서는 PageDown 키가 눌렸는지 확인합니다. 그렇다면 z 변수의 값을 늘립니다. 이런 식으로 DrawGLScene 함수에 포함된 glTranslatef(0.0f,0.0f,z) 호출은 나무 상자를 관찰자에게 더 가깝게 이동시킵니다.
If 키[VK_NEXT] Then // PageDown이 눌렸습니까?
z := z + 0.02; //누르면 나무 상자를 관찰자 쪽으로 이동합니다.
//이제 화살표 키를 확인합니다. 왼쪽 및 오른쪽 방향 키를 누르면 xspeed가 그에 따라 감소하거나 증가합니다.
//위쪽 및 아래쪽 방향 키를 눌러 yspeed를 적절하게 줄이거나 늘립니다.
//향후 튜토리얼에서는 xspeed와 yspeed의 값이 증가하면 큐브가 더 빠르게 회전한다는 점을 기억하세요.
//특정 방향 키를 계속 누르고 있으면 해당 방향으로 큐브가 더 빠르게 회전합니다.
If 키[VK_UP] Then // 위쪽 방향 키가 눌렸습니까?
xspeed := xspeed - 0.01; //그렇다면 xspeed를 줄입니다.
If 키[VK_DOWN] Then //아래 방향 키가 눌렸습니까?
xspeed := xspeed + 0.01; //그렇다면 xspeed를 높입니다.
If 키[VK_RIGHT] Then //오른쪽 방향 키가 눌렸습니까?
yspeed := yspeed + 0.01; //그렇다면 yspeed를 높입니다.
If 키[VK_LEFT] Then //왼쪽 방향 키가 눌렸습니까?
yspeed := yspeed - 0.01; //그렇다면 yspeed를 줄입니다.
If (keys[VK_ESCAPE]) Then // ESC 키를 누른 경우
완료 := 사실
실행해보고 효과를 확인해보세요