glActiveTexture와 glBindTexture의 차이점과 관계


137

내가 수집 한 것에서 glActiveTexture활성 "텍스처 유닛"을 설정합니다. 각 텍스처 유닛은 여러 텍스처 타겟 (일반적으로 GL_TEXTURE_1D, 2D, 3D 또는 CUBE_MAP)을 가질 수 있습니다.

올바르게 이해하면 glActiveTexture먼저 텍스처 단위를 (초기화 됨 GL_TEXTURE0) 로 설정 한 다음 해당 텍스처 단위에 "텍스처 대상"을 하나 이상 바인딩해야합니까?

사용 가능한 텍스처 단위의 수는 시스템에 따라 다릅니다. 내 라이브러리에는 최대 32 개의 열거 형이 표시됩니다. 나는 이것이 본질적으로 내 GPU 한계를 줄일 수 있음을 의미한다고 생각합니다.168) GPU 메모리에 한 번에 32 개의 텍스처가 있습니까? GPU의 최대 메모리 (약 1GB)를 초과하지 않는 추가 제한이 있다고 생각합니다.

텍스처 대상과 텍스처 단위 사이의 관계를 올바르게 이해하고 있습니까? 16 개 유닛과 4 개의 타겟을 각각 허용한다고 가정 해 봅시다. 16 * 4 = 64 개의 타겟을위한 공간이 있거나 그렇게 작동하지 않습니까?

다음으로 일반적으로 텍스처를로드하려고합니다. 를 통해이 작업을 수행 할 수 있습니다 glTexImage2D. 첫 번째 인수는 텍스처 대상입니다. 이것이 작동glBufferData 하면 "핸들"/ "텍스처 이름"을 텍스처 대상에 바인딩 한 다음 텍스처 데이터를 해당 대상에로드하여 해당 핸들과 간접적으로 연결합니다.

무엇에 대해 glTexParameter? 텍스처 대상을 바인딩 한 다음 첫 번째 인수와 동일한 대상을 다시 선택해야합니까? 또는 올바른 활성 텍스처 단위가있는 한 텍스처 대상을 바인딩 할 필요가 없습니까?

glGenerateMipmap 타겟에서도 작동합니다. 타겟이 여전히 텍스처 이름에 바인딩되어 있어야 성공할 수 있습니까?

그런 다음 텍스처로 오브젝트를 그리려면 활성 텍스처 단위와 텍스처 대상 을 모두 선택 해야 합니까? 또는 텍스처 단위를 선택한 다음 해당 단위와 관련된 4 개의 대상 중 하나에서 데이터를 가져올 수 있습니까? 이것은 정말 혼란스러운 부분입니다.

답변:


259

OpenGL 객체에 관한 모든 것

OpenGL 객체의 표준 모델은 다음과 같습니다.

객체에는 상태가 있습니다. 그것들을로 생각하십시오 struct. 따라서 다음과 같이 정의 된 객체가있을 수 있습니다.

struct Object
{
    int count;
    float opacity;
    char *name;
};

객체에는 특정 값이 저장되어 있으며 상태가 있습니다. OpenGL 객체도 상태가 있습니다.

상태 변경

C / C ++에서 유형의 인스턴스가있는 경우 Object상태를 다음과 같이 변경합니다. obj.count = 5;객체의 인스턴스를 직접 참조하고 변경하려는 특정 상태를 가져 와서 값을 입력합니다.

OpenGL에서는이 작업수행하지 않습니다 .

설명 할 수없는 더 나은 왼쪽 레거시 이유는, OpenGL을 객체의 상태를 변경하려면, 먼저해야 바인드 그 문맥에. 이것은 일부 glBind*전화로 이루어집니다 .

이에 해당하는 C / C ++는 다음과 같습니다.

Object *g_objs[MAX_LOCATIONS] = {NULL};    
void BindObject(int loc, Object *obj)
{
  g_objs[loc] = obj;
}

질감은 흥미 롭습니다. 그것들은 특별한 바인딩의 경우를 나타냅니다. 많은 glBind*통화에는 "대상"매개 변수가 있습니다. 이것은 OpenGL 컨텍스트에서 해당 유형의 객체를 바인딩 할 수있는 다른 위치를 나타냅니다. 예를 들어, 읽기 ( GL_READ_FRAMEBUFFER) 또는 쓰기 ( GL_DRAW_FRAMEBUFFER) 를 위해 프레임 버퍼 객체를 바인딩 할 수 있습니다 . 이는 OpenGL이 버퍼를 사용하는 방법에 영향을줍니다. 이것이 loc위 의 매개 변수가 나타내는 것입니다.

텍스처는 대상에 처음 바인딩 할 때 특별한 정보를 얻기 때문에 특별합니다. 텍스처를 처음으로 바인딩하면 GL_TEXTURE_2D실제로 텍스처에서 특수 상태를 설정하는 것입니다. 이 텍스처는 2D 텍스처입니다. 그리고 항상 2D 텍스처입니다. 이 상태는 변경할 수 없습니다 지금 . 으로 처음 바인딩 된 텍스처가있는 경우 항상 ; 로 바인딩 GL_TEXTURE_2D해야합니다 . 바인딩을 시도 하면 오류가 발생합니다 (런타임 동안).GL_TEXTURE_2DGL_TEXTURE_1D

객체가 바인딩되면 상태를 변경할 수 있습니다. 이는 해당 객체에 고유 한 일반 기능을 통해 수행됩니다. 또한 수정할 개체를 나타내는 위치를 사용합니다.

C / C ++에서는 다음과 같습니다.

void ObjectParameteri(int loc, ObjectParameters eParam, int value)
{
  if(g_objs[loc] == NULL)
    return;

  switch(eParam)
  {
    case OBJECT_COUNT:
      g_objs[loc]->count = value;
      break;
    case OBJECT_OPACITY:
      g_objs[loc]->opacity = (float)value;
      break;
    default:
      //INVALID_ENUM error
      break;
  }
}

이 함수가 현재 바인드 된 loc값으로 발생하는 것을 어떻게 설정하는지 주목하십시오 .

텍스처 오브젝트의 경우 주요 텍스처 상태 변경 기능은 glTexParameter입니다. 텍스처 상태를 변경하는 유일한 다른 함수는 glTexImage함수와 그 변형 ( glCompressedTexImage,, glCopyTexImage최근 glTexStorage)입니다. 다양한 SubImage버전은 텍스처의 내용을 변경하지만 기술적으로 상태를 변경하지는 않습니다 . Image기능 텍스쳐 저장 공간을 할당하고 텍스처의 포맷을 설정; SubImage기능은 픽셀을 주변에 복사합니다. 텍스처 상태로 간주되지 않습니다.

반복하겠습니다 : 텍스처 상태를 수정 하는 유일한 기능입니다. glTexEnv환경 상태를 수정합니다. 텍스처 오브젝트에 저장된 것에 영향을 미치지 않습니다.

활성 텍스처

텍스처의 상황은 더 복잡하지만, 레거시 이유로 공개되지 않은 것이 가장 많습니다. 여기가 glActiveTexture온다.

텍스처를 들어, 단지 목표는 (가 아니다 GL_TEXTURE_1D, GL_TEXTURE_CUBE_MAP등). 텍스처 단위도 있습니다. C / C ++ 예제와 관련하여 우리가 가진 것은 다음과 같습니다.

Object *g_objs[MAX_OBJECTS][MAX_LOCATIONS] = {NULL};
int g_currObject = 0;

void BindObject(int loc, Object *obj)
{
  g_objs[g_currObject][loc] = obj;
}

void ActiveObject(int currObject)
{
  g_currObject = currObject;
}

이제 2D 목록 Object뿐만 아니라 현재 객체의 개념도 있습니다. 현재 개체를 설정하는 기능이 있고, 최대 현재 개체 수라는 개념이 있으며, 모든 개체 조작 기능이 현재 개체에서 선택하도록 조정되었습니다.

현재 활성화 된 객체를 변경하면 전체 대상 위치 세트가 변경됩니다. 따라서 현재 객체 0에 들어가는 것을 바인딩하고 현재 객체 4로 전환하면 완전히 다른 객체를 수정할 수 있습니다.

텍스처 오브젝트와의이 비유는 거의 완벽합니다.

참조 glActiveTexture정수를하지 않습니다; 열거자가 필요합니다 . 그것에서 아무것도 걸릴 수 있다는 이론 수단에 어떤 GL_TEXTURE0에가 GL_TEXTURE31. 그러나 이해해야 할 것이 하나 있습니다.

이것은 거짓입니다!

glActiveTexture취할 수 있는 실제 범위 는에 의해 결정됩니다 GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS. 이는 구현이 허용하는 최대 동시 다중 텍스처 수입니다. 이들은 각각 다른 셰이더 단계에 대해 서로 다른 그룹으로 나뉩니다. 예를 들어 GL 3.x 클래스 하드웨어에서는 16 개의 정점 셰이더 텍스처, 16 개의 조각 셰이더 텍스처 및 16 개의 지오메트리 셰이더 텍스처가 제공됩니다. 따라서 GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS48입니다.

그러나 48 개의 열거자는 없습니다. 이것이 glActiveTexture실제로 열거자를 사용하지 않는 이유 입니다. 올바른 호출 방법은 glActiveTexture다음과 같습니다 :

glActiveTexture(GL_TEXTURE0 + i);

여기서 i0과 사이의 숫자 GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS입니다.

표현

이 모든 것이 렌더링과 어떤 관련이 있습니까?

셰이더를 사용하는 경우 샘플러 유니폼을 텍스처 이미지 단위 ( glUniform1i(samplerLoc, i), 여기서 i이미지 단위)로 설정하십시오. 사용하는 숫자를 나타냅니다 glActiveTexture. 샘플러는 샘플러 유형에 따라 대상을 선택합니다. 그래서 목표 sampler2D에서 선택합니다 GL_TEXTURE_2D. 이것이 샘플러의 유형이 다른 이유 중 하나입니다.

이제 동일한 텍스처 이미지 단위를 사용하는 유형 이 다른 두 개의 GLSL 샘플러를 사용할 수있는 것처럼 들립니다 . 그러나 당신은 할 수 없습니다; OpenGL은이를 금지하고 렌더링을 시도 할 때 오류를 발생시킵니다.


12
와! 또 다른 훌륭한 답변-감사합니다 Nicol! 특히 2D 텍스처에 관한 단락은 항상 2D 텍스처입니다. 나는 지금 이러한 것들 중 일부를 감싸는 래퍼를 만들고 있는데 변경을 위해 열어 두어야하는지 확실하지 않았다. 그리고 그 부분은 GL_TEXTURE0 + i-열거 형 값을 검사하여 그것이 유효한지 아닌지를 확인하는 것이 었습니다. 그리고 마지막 단락-그것이 합법적인지 알지 못했습니다. 우수한! 모든 답변을 북마크에 추가하여 다시 참조 할 수 있습니다.
mpen

6
@Nicol Bolas : 이것은 잘 설명되어 있습니다. 이 중 일부를 온라인 OpenGL 서적의 텍스처 장에 복사해야합니다. 나는 이것이 훨씬 명확하고 장을 잘 칭찬 할 것이라고 생각합니다.
WesDec

3
@Nicol Bolas 저는 OpenGL을 배우기 시작했고이 답변이 저에게 많은 도움이되었습니다. 감사합니다!
인라인

2
니코 이봐, 당신의 작은 오타를 지적 할 : 그것의 GL_DRAW_FRAMEBUFFER하지 GL_WRITE_FRAMEBUFFER을
Defd

3
@Nicol : 와우, 내가 지금까지 가지고 있었던 최고의 정의는 당신의 arcsynthesis 튜토리얼에서 왔습니다. 이제 당신은 그 훌륭한 소스를 능가했습니다. 감사합니다
Baggers

20

시도해 볼게요! 이 모든 것이 그렇게 복잡하지 않고 용어의 문제 일뿐입니다.


시스템에 사용 가능한 메모리가있는만큼 텍스처 개체 를 대략적으로 만들 수 있습니다 . 이 오브젝트는 텍스처의 실제 데이터 (텍셀)와 glTexParameter가 제공하는 파라미터 ( FAQ 참조 )를 보유합니다.

생성되는 경우, 하나의 할당해야 텍스처 대상 텍스처의 유형을 나타내는 하나의 텍스처 객체에 ( GL_TEXTURE_2D, GL_TEXTURE_3D, GL_TEXTURE_CUBE, ...).

이 두 항목 인 텍스처 오브젝트텍스처 대상 은 텍스처 데이터를 나타냅니다. 나중에 다시 연락 드리겠습니다.

텍스처 유닛

이제 OpenGL은 텍스쳐 유닛 배열을 제공하며 , 그리는 동안 동시에 사용할 수 있습니다. 배열의 크기는 OpenGL 시스템에 따라 다르며 8이 있습니다.

당신은 할 수 있습니다 결합 그리는 동안 주어진 텍스처를 사용하여 텍스처 유닛에 텍스처 개체를.

간단하고 쉬운 세계에서 주어진 텍스처로 그리려면 텍스처 오브젝트를 텍스처 유닛에 바인딩하고 (의사 코드)를 수행합니다.

glTextureUnit[0] = textureObject

GL은 상태 머신이기 때문에 아쉽게도 이런 식으로 작동하지 않습니다. 텍스처 대상에 textureObject대한 데이터가 있다고 가정하면 GL_TEXTURE_2D이전 할당을 다음과 같이 표현합니다.

glActiveTexture(GL_TEXTURE0);                   // select slot 0 of the texture units array
glBindTexture(GL_TEXTURE_2D, textureObject);    // do the binding

GL_TEXTURE_2D정말 당신이 결합 할 질감의 유형에 따라 달라집니다.

텍스처 오브젝트

의사 코드에서 텍스처 데이터 또는 텍스처 매개 변수를 설정하려면 다음과 같이하십시오.

setTexData(textureObject, ...)
setTexParameter(textureObject, TEXTURE_MIN_FILTER, LINEAR)

OpenGL은 텍스처 객체를 직접 조작하거나, 내용을 업데이트 / 설정하거나, 매개 변수를 변경하기 위해 먼저 활성 텍스처 유닛 (둘 중 어느 쪽이든)에 바인딩해야합니다. 동등한 코드는 다음과 같습니다.

glBindTexture(GL_TEXTURE_2D, textureObject)       // this 'installs' textureObject in texture unit
glTexImage2D(GL_TEXTURE_2D, ...)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)

셰이더

셰이더는 모든 텍스처 단위에 액세스 할 수 있으며 활성 텍스처에는 신경 쓰지 않습니다.

샘플러 유니폼은 int샘플러 (및 사용 감촉 유닛의 인덱스를 나타내는 값 하지 사용할 텍스처 객체).

따라서 텍스처 오브젝트를 사용하려는 유닛에 바인딩해야합니다.

샘플러의 유형은 텍스처 단위에 사용되는 텍스처 대상과 일치합니다 : Sampler2Dfor GL_TEXTURE_2D


내가 이해하지 못하는 한 가지. 텍스처가 있고 다른 텍스처 단위의 많은 쉐이더에 사용된다고 가정 해 봅시다. 런타임에 텍스처 필터링을 변경하고 싶다고 가정 해 봅시다. 어떤 텍스처 단위를 사용해야합니까? Unit 0에서 텍스처 상태를 변경 한 다음 다른 텍스처에서 해당 텍스처를 사용할 수 있습니까?
majakthecoder

@ majakthecoder 내 대답에서는 필터링을 텍스처 객체 의 속성으로 간주합니다. 즉, 텍스처 단위에서 구체적으로 변경할 수 없습니다. 대상으로하는 OpenGL의 특징에 따라이 문제를 해결하기 위해 객체샘플링 할 수 있습니다 ( opengl.org/wiki/Sampler_Object ). 그렇지 않으면 텍스처 객체를 복제하여 여러 개의 동시 필터링을 수행해야 할 수도 있습니다.
rotoglup

12

페인트 처리 공장과 같은 GPU를 상상해보십시오.

일부 페인트 탱크에는 염료가 일부 페인트 기계에 전달됩니다. 페인팅 기계에서 염료는 물체에 적용됩니다. 그 탱크는 텍스처 단위입니다

이 탱크에는 다양한 종류의 염료가 장착 될 수 있습니다. 각 종류의 염료에는 다른 종류의 용매가 필요합니다. "용매"는 텍스처 대상 입니다. 편의상 각 탱크는 일부 솔벤트 공급 장치에 연결되어 있지만 각 탱크에서 한 번에 한 종류의 솔벤트 만 사용할 수 있습니다. 따라서 밸브 / 스위치가있다 TEXTURE_CUBE_MAP, TEXTURE_3D, TEXTURE_2D, TEXTURE_1D. 모든 염료 유형을 동시에 탱크에 채울 수 있지만 한 종류의 용매 만 들어가기 때문에 염료 일치 유형 만 "희석"합니다. 따라서 각 종류의 텍스처를 바인딩 할 수 있지만 "가장 중요한"솔벤트와의 바인딩은 실제로 탱크에 들어가서 해당 염료의 종류와 혼합됩니다.

그리고 창고에서 나온 염료 자체가 있으며,이를“바인딩”하여 탱크에 채 웁니다. 그게 당신의 질감입니다.


2
이상한 유추의 종류 ... 나는 그것이 실제로 무엇을 지우는 지 확신 할 수 없습니다. 특히 "희석"과 "가장 중요한 용매"에 관한 부분. 2D 텍스처와 3D 텍스처를 모두 바인딩하면 둘 중 하나만 사용할 수 있습니까? 어느 것이 가장 중요하다고 생각됩니까?
mpen

2
@ 마크 : 글쎄, 나는 문자 염료 (유성 및 수성)와 함께 일하는 화가의 관점에서 말하려고했습니다. 어쨌든 여러 텍스처 대상을 바인딩하고 활성화하면 CUBE_MAP> 3D> TEXTURE_ARRAY> 2D> 1D가 우선합니다.
datenwolf

1
산뜻한! 나는 우선 순위에 대해 몰랐다. 텍스처 단위당 하나의 텍스처 대상 만 사용할 수 있다는 것을 알았으므로 더 의미가 있습니다.
mpen

1
@ legends2k : 글쎄, 이제 점점 흥미로워지고 있습니다. 핵심 또는 호환성 프로파일에 대해 이야기하고 있습니까? 이상적이거나 버그가 많은 드라이버를 가정합니까? 이론적으로 유니폼의 유형은 선택할 텍스처 단위의 대상을 선택합니다. 실제로 이것은 핵심 프로파일에서 발생합니다. 호환성 프로파일에서 일부 버기 드라이버는 텍스처 단위의 이전 대상이 샘플러의 유형과 일치하지 않는 경우 모든 흰색 기본 텍스처를 표시합니다.
datenwolf

1
@ legends2k : 또한 같은 단위에 2D와 3D 텍스처가 바인딩되어 있고 같은 단위에 2D와 3D 샘플러 유니폼이 있다면 어떻게 될지 생각해보십시오. 이것으로 모든 종류의 이상한 드라이버 버그를 유발할 수 있습니다. 실제로 이전의 고정 함수 우선 순위 모델에서 생각하면 정신이 상하고 프로그램이 작동합니다. 대부분의 운전자가 예측 가능한 방식으로 행동하기 때문입니다.
datenwolf

2

셰이더에있는 경우 2 개의 텍스처에서 조회해야합니다.

uniform sampler2D tex1;  
uniform sampler2D tex2;  

tex1 및 tex2에 대해 다음과 같이 소스를 표시해야합니다.

tex1 = gl.createTexture();  
gl.activeTexture(gl.TEXTURE3);  
gl.bindTexture(gl.TEXTURE_2D, tex1); 
gl.texParameteri(gl.TEXTURE_2D, ...);  
....


tex2 = gl.createTexture();  
gl.activeTexture(gl.TEXTURE7);  
gl.bindTexture(gl.TEXTURE_2D, tex2); 
gl.texParameteri(gl.TEXTURE_2D, ...);  
....  
var tex1Loc  = gl.getUniformLocation(your_shader,"tex1");  
var tex2Loc  = gl.getUniformLocation(your_shader,"tex2");

렌더 루프에서 :

gl.uniform1i(tex1Loc, 3);  
gl.uniform1i(tex2Loc, 7);  
// but you can dynamically change these values

gl_bindtexture를 사용하면 그러한 일을 할 수 없습니다. 반면에 렌더링 루프에서 바인드를 사용하는 것은 스트림 (비디오, 웹캠)의 내용으로 텍스처를 공급하는 경우입니다.

gl.bindTexture(gl.TEXTURE_2D, tex1);  
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, video);  
// in the render loop
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.