{
하하, 이 두 레슨은 번역된 지 오래됐는데 아직 안 올라왔네요. 다들 오래 기다리셨죠. (더 이상 기다리시는 분 없으신가요?)
단순한 투명성
OpenGL의 대부분의 특수 효과는 특정 유형의 (색상) 혼합과 관련이 있습니다.
색상 혼합은 특정 픽셀의 색상과 화면에 그려진 해당 픽셀의 색상을 결합하는 것으로 정의됩니다.
두 색상이 결합되는 방식은 색상의 알파 채널 구성 요소 값 및/또는 사용된 색상 혼합 기능에 따라 달라집니다.
알파는 일반적으로 색상 값 끝의 4번째 색상 구성요소입니다.
이전 수업에서는 GL_RGB를 사용하여 색상의 세 가지 구성 요소를 지정했습니다.
해당 GL_RGBA는 알파 구성 요소의 값을 지정할 수 있습니다.
한 단계 더 나아가 glColor3f() 대신 glColor4f()를 사용할 수 있습니다.
대부분의 사람들은 알파 구성요소가 재료의 투명도를 나타낸다는 데 동의합니다.
즉, 알파 값 0.0은 완전히 투명한 재질을 나타냅니다.
알파 값 1.0은 완전히 불투명한 재질을 나타냅니다.
색상 혼합 공식
수학에 관심이 없고 투명성을 얻는 방법만 알고 싶다면 이 섹션을 건너뛰세요.
(색상) 혼합이 어떻게 작동하는지 더 깊이 이해하고 싶다면 이 섹션이 도움이 될 것입니다.
『CKER의 덧붙임: 사실 어렵지 않아요^-^. 원문의 공식은 다음과 같습니다. CKER에서 다시 설명하겠습니다.
실제로 혼합의 기본 원리는 RGB 규칙에 따라 각 픽셀의 색상과 분리하려는 이미지의 배경색을 분리하는 것입니다.
- 이미지의 RGB 색상 구성요소 * 알파 값 + 배경의 RGB 색상 구성요소 * (1-알파 값)에 따라
- 이렇게 간단한 공식으로 혼합한 후, 혼합하여 얻은 RGB 성분들이 최종적으로 다시 병합됩니다. 』
공식은 다음과 같습니다.
(Rs Sr + Rd Dr, Gs Sg + Gd Dg, Bs Sb + Bd Db, As Sa + Ad Da)
OpenGL은 위 공식에 따라 두 픽셀의 색상 혼합 결과를 계산합니다.
소문자 s와 r은 각각 소스 픽셀과 대상 픽셀을 나타냅니다. 대문자 S와 D는 해당 색상 혼합 요소입니다.
이는 해당 픽셀의 색상을 혼합하는 방법을 결정합니다.
대부분의 경우 각 색상 채널의 알파 믹싱 값은 동일합니다.
이런 식으로 소스 픽셀에 대해 (As, As, As, As)를 갖게 됩니다.
대상 픽셀은 1, 1, 1, 1) - (As, As, As, As)입니다.
위의 공식은 다음과 같습니다.
(Rs As + Rd(1 - As), Gs As + Gd(1 - As), Bs As + Bs(1 - As), As + Ad(1 - As))
이 공식은 투명/반투명 효과를 만들어냅니다.
OpenGL의 색상 혼합
OpenGL에서 색상 혼합을 구현하는 단계는 이전에 언급한 OpenGL 프로세스와 유사합니다.
그런 다음 투명 개체를 그릴 때 공식을 설정하고 쓰기 깊이 캐시를 끄십시오.
반투명한 모양 뒤에 개체를 그리고 싶기 때문입니다.
이는 색상을 혼합하는 올바른 방법은 아니지만 대부분의 경우 간단한 프로젝트에서는 잘 작동합니다.
Rui Martins의 추가: 올바른 색상 혼합 프로세스는 전체 장면을 먼저 그린 다음 투명 그래픽을 그리는 것입니다.
그리고 깊이 버퍼의 역순으로 그려집니다(가장 먼 객체가 먼저 그려집니다).
두 개의 다각형(1과 2)을 알파 블렌딩하는 것을 고려하면 그리기 순서가 다르면 결과도 달라집니다.
(여기서는 다각형 1이 관찰자에게 가장 가깝다고 가정하고 올바른 프로세스에서는 다각형 2를 먼저 그린 다음 다각형 1을 그려야 합니다.
현실에서 볼 수 있듯이,
이 두 <투명> 다각형 뒤에서 나오는 빛은 항상 다각형 2를 먼저 통과합니다.
그런 다음 다각형 1을 통과하고 마침내 관찰자의 눈에 도달합니다. )
깊이 캐싱이 활성화되면 투명 그래픽을 깊이별로 정렬해야 합니다.
그리고 모든 장면이 그려진 후에 이러한 투명한 개체를 그립니다. 그렇지 않으면 잘못된 결과를 얻게 됩니다.
가끔 이렇게 하는 것이 고통스럽다는 것을 알지만, 그렇게 하는 것이 올바른 방법입니다.
7강의 코드를 사용하겠습니다.
코드 시작 부분에 두 개의 새 변수를 추가하여 시작하세요. 명확성을 위해 전체 코드를 다시 작성했습니다.
}
바르
h_RC: HGLRC; // 렌더링 컨텍스트(쉐이딩 설명 테이블).
h_DC: HDC; // 장치 컨텍스트(장치 설명 테이블)
h_Wnd: HWND; // 창 핸들
h_Instance: HINST; // 프로그램 인스턴스(인스턴스).
키 : Array[0..255] Of Boolean // 키보드 루틴용 배열;
light : 부울; // 광원 켜기/끄기
blend : Boolean; // 블렌딩 끄기/켜기(신규)
lp : Boolean; // L 키가 눌렸나요?
fp : Boolean; // F 키가 눌렸나요?
bp : Boolean; // B 키가 눌렸나요? (신규)
xrot : GLfloat; // X 회전
yrot : GLfloat; // Y 회전
xspeed : GLfloat; // X 회전 속도
yspeed : GLfloat; // Y 회전 속도
z : GLfloat = -5.0 f; // 화면 깊은 곳까지의 거리
LightAmbient: Array[0..3] Of GLfloat = (0.5, 0.5, 0.5, 1.0) //주변광 매개변수(신규)
LightDiffuse: Array[0..3] Of GLfloat = (1.0, 1.0, 1.0, 1.0) // 확산 조명 매개변수(신규)
LightPosition: Array[0..3] Of GLfloat = (0.0, 0.0, 2.0, 1.0) // 광원 위치(신규)
filter : GLuint; // 필터 유형
텍스처 : GLuint의 배열[0..2] // 텍스처 3개를 위한 저장 공간
PRocedure glGenTextures(n: GLsizei; Var 텍스처: GLuint);
OpenGL32;
절차 glBindTexture(대상: GLenum; 텍스처: GLuint);
OpenGL32;
함수 gluBuild2DMipmaps(대상: GLenum; 구성 요소, 너비, 높이: GLint;
형식, atype: GLenum; 데이터: 포인터): 외부 glu32 이름;
'gluBuild2DMipmaps';
{
그런 다음 LoadGLTextures()로 이동합니다.
(TextureImage[0]=LoadBMP('Data/Crate.bmp'))인지 확인하세요.
이 줄. 이제 이전 단원의 나무 상자 텍스처 대신 착색된 유리 텍스처를 사용하고 있습니다.
if (TextureImage[0]=LoadBMP("Data/glass.bmp")); // 유리 비트맵 로드(수정됨)
}
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]); // 텍스처 생성
// 가장 가까운 필터 맵 생성
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);
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) // 선형 필터링
//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) // (신규)
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; // 이미지 구조 해제
결과 := 상태; // 상태 반환
끝;
{
glInit() 코드 섹션에 다음 두 줄을 추가합니다.
첫 번째 줄은 이 객체를 최대 밝기로 그리고 50% 알파 블렌딩(반투명)을 제공합니다.
블렌딩 옵션이 켜져 있으면 이 개체는 50% 투명해집니다.
두 번째 줄은 사용되는 블렌딩 유형을 설정합니다.
Rui Martins가 추가했습니다.
알파 채널 값이 0.0이면 개체의 재질이 완전히 투명하다는 의미입니다.
1.0은 완전히 불투명함을 의미합니다.
}
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); //매우 최적화된 원근 투영 계산
glLightfv(GL_LIGHT1, GL_AMBIENT, @LightAmbient[0]) // 주변광 설정
glLightfv(GL_LIGHT1, GL_DIFFUSE, @LightDiffuse[0]) // 확산광 설정
glLightfv(GL_LIGHT1, GL_POSITION, @LightPosition); // 광원 위치
glEnable(GL_LIGHT1); // 1번 광원 활성화
glColor4f(1.0, 1.0, 1.0, 0.5); // 전체 밝기, 50% 알파 블렌딩(신규)
glBlendFunc(GL_SRC_ALPHA, GL_ONE); // 소스 픽셀의 알파 채널 값을 기반으로 하는 반투명 블렌딩 함수(신규)
끝;
{7강이 끝날 무렵에 다음 코드 스니펫을 찾으세요.
If 키[VK_LEFT] Then //왼쪽 방향 키가 눌렸습니까?
yspeed := yspeed - 0.01; //그렇다면 yspeed를 줄입니다.
위의 코드에 이어 다음 코드를 추가합니다.
이 줄은 B 키를 눌렀는지 여부를 모니터링합니다.
그렇다면 컴퓨터는 혼합 옵션이 켜져 있는지 확인합니다.
그런 다음 반대 상태로 설정합니다.
}
If (keys[ord('B')] And Not bp) Then //B 키를 눌렀는데 bp가 FALSE인가요?
시작하다
bp := TRUE; // 그렇다면 bp는 TRUE로 설정됩니다.
blend := 혼합하지 않음; // 혼합 옵션을 TRUE / FALSE로 전환합니다.
If (blend) Then // 블렌딩이 켜져 있습니까?
시작하다
glEnable(GL_BLEND); // 블렌딩 켜기
glDisable(GL_DEPTH_TEST); // 깊이 테스트 끄기
끝
그렇지 않으면 // 그렇지 않으면
시작하다
glDisable(GL_BLEND); // 블렌딩을 끕니다.
glEnable(GL_DEPTH_TEST); // 깊이 테스트 켜기
끝;
끝;
If (Notkey[ord('B')]) Then // B 키가 해제되었습니까?
시작하다
bp := FALSE; // 그렇다면 bp를 FALSE로 설정합니다.
끝;
{
하지만 텍스처 매핑을 사용할 때 블렌드 색상을 어떻게 지정할 수 있습니까? 매우 간단합니다.
텍스처 모드를 조정할 때 텍스처 텍스처의 각 픽셀 색상은 알파 채널 매개변수에 의해 결정됩니다.
현재 픽셀 색상을 곱하여 얻습니다.
예를 들어 그려지는 색상은 (0.5, 0.6, 0.4),
색상을 곱하여 (0.5, 0.6, 0.4, 0.2)를 얻습니다.
(alpha 매개변수가 지정되지 않은 경우 기본값은 0입니다.)
그게 다야! OpenGL에서 알파 블렌딩을 구현하는 것은 실제로 매우 간단합니다!
}
{
원본 메모(99년 11월 13일)
표시된 개체가 더욱 사실적으로 보이도록 내(NeHe) 색상 혼합 코드가 수정되었습니다.
알파 매개변수를 사용하여 소스 픽셀과 대상 픽셀을 동시에 혼합하면 개체의 인공 흔적이 뚜렷하게 보입니다.
이렇게 하면 개체의 뒷면이 측면을 따라 더 어둡게 나타납니다.
기본적으로 개체는 이상하게 보일 것입니다.
제가 사용한 색상 혼합 방법이 최고는 아닐 수도 있지만 효과는 있습니다.
조명을 활성화하면 객체가 사실적으로 보입니다.
원래 코드를 제공한 Tom에게 감사드립니다. 그가 사용한 색상 혼합 방법이 정확합니다.
하지만 그 물체는 기대만큼 매력적으로 보이지는 않습니다 :)
일부 그래픽 카드의 glDepthMask() 함수 관련 문제를 해결하여 코드가 다시 수정되었습니다.
이 명령은 일부 카드에서 깊이 버퍼 테스트를 활성화하거나 비활성화할 때 그다지 효과적이지 않은 것 같습니다.
그래서 깊이 버퍼 테스트를 활성화하거나 비활성화하는 코드를 구식 glEnable 및 glDisable로 변환했습니다.
텍스처 맵의 알파 블렌딩
텍스처 맵에 사용되는 알파 매개변수는 색상과 마찬가지로 문제 맵에서 읽을 수 있습니다.
방법은 다음과 같습니다. 필요한 재질을 로드하고 동시에 해당 알파 매개변수를 가져와야 합니다.
그런 다음 glTexImage2D()를 호출할 때 GL_RGBA의 색상 형식을 사용하십시오.
}