glActiveTexture와 glBindTexture의 차이점과 관계
내가 수집 한 것에서 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 개의 대상 중 하나에서 데이터를 가져올 수 있습니까? 이것은 정말 혼란스러운 부분입니다.
OpenGL 객체에 관한 모든 것
OpenGL 객체의 표준 모델은 다음과 같습니다.
객체에는 상태가 있습니다. 그것들을로 생각하십시오 struct
. 따라서 다음과 같이 정의 된 객체가있을 수 있습니다.
struct Object
{
int count;
float opacity;
char *name;
};
객체에는 특정 값이 저장되어 있으며 상태가 있습니다. OpenGL 객체도 상태가 있습니다.
상태 변경
C / C ++에서 type의 인스턴스가있는 경우 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_2D
GL_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;
}
}
Notice how this function sets whatever happens to be in currently bound loc
value.
For texture objects, the main texture state changing functions are glTexParameter
. The only other functions that change texture state are the glTexImage
functions and their variations (glCompressedTexImage
, glCopyTexImage
, the recent glTexStorage
). The various SubImage
versions change the contents of the texture, but they do not technically change its state. The Image
functions allocate texture storage and set the texture's format; the SubImage
functions just copy pixels around. That is not considered the texture's state.
Allow me to repeat: these are the only functions that modify texture state. glTexEnv
modifies environment state; it doesn't affect anything stored in texture objects.
Active Texture
The situation for textures is more complex, again for legacy reasons best left undisclosed. This is where glActiveTexture
comes in.
For textures, there aren't just targets (GL_TEXTURE_1D
, GL_TEXTURE_CUBE_MAP
, etc). There are also texture units. In terms of our C/C++ example, what we have is this:
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;
}
Notice that now, we not only have a 2D list of Object
s, but we also have the concept of a current object. We have a function to set the current object, we have the concept of a maximum number of current objects, and all of our object manipulation functions are adjusted to select from the current object.
When you change the currently active object, you change the entire set of target locations. So you can bind something that goes into current object 0, switch to current object 4, and will be modifying a completely different object.
This analogy with texture objects is perfect... almost.
See, glActiveTexture
does not take an integer; it takes an enumerator. Which in theory means that it can take anything from GL_TEXTURE0
to GL_TEXTURE31
. But there's one thing you must understand:
THIS IS FALSE!
The actual range that glActiveTexture
can take is governed by GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS
. That is the maximum number of simultaneous multitextures that an implementation allows. These are each divided up into different groupings for different shader stages. For example, on GL 3.x class hardware, you get 16 vertex shader textures, 16 fragment shader textures, and 16 geometry shader textures. Therefore, GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS
will be 48.
But there aren't 48 enumerators. Which is why glActiveTexture
doesn't really take enumerators. The correct way to call glActiveTexture
is as follows:
glActiveTexture(GL_TEXTURE0 + i);
where i
is a number between 0 and GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS
.
Rendering
So what does all of this have to do with rendering?
When using shaders, you set your sampler uniforms to a texture image unit (glUniform1i(samplerLoc, i)
, where i
is the image unit). That represents the number you used with glActiveTexture
. The sampler will pick the target based on the sampler type. So a sampler2D
will pick from the GL_TEXTURE_2D
target. This is one reason why samplers have different types.
Now this sounds suspiciously like you can have two GLSL samplers, with different types that use the same texture image unit. But you can't; OpenGL forbids this and will give you an error when you attempt to render.
I'll give it a try ! All this is not that complicated, just a question of terms, hope I'll make myself clear.
You can create roughly as many Texture Objects as there is available memory in your system. These objects hold the actual data (texels) of your textures, along with parameters, provided by glTexParameter (see FAQ).
When being created, you have to assign one Texture Target to one texture object, which represents the type of the texture (GL_TEXTURE_2D
, GL_TEXTURE_3D
, GL_TEXTURE_CUBE
, ...).
These two items, texture object and texture target represent the texture data. We'll come back to them later.
Texture units
Now, OpenGL provides an array of texture units, that can be used simultaneously while drawing. The size of the array depends of the OpenGL system, yours has 8.
You can bind a texture object to a texture unit to use the given texture while drawing.
In a simple and easy world, to draw with a given texture, you'd bind a texture object to the texture unit, and you'd do (pseudocode):
glTextureUnit[0] = textureObject
As GL is a state machine, it, alas, does not work this way. Supposing that our textureObject
has data for the GL_TEXTURE_2D
texture target, we'll express the previous assignment as :
glActiveTexture(GL_TEXTURE0); // select slot 0 of the texture units array
glBindTexture(GL_TEXTURE_2D, textureObject); // do the binding
Note that GL_TEXTURE_2D
really depends on the type of the texture you want to bind.
Texture objects
In pseudo code, to set texture data or texture parameters, you'd do for example :
setTexData(textureObject, ...)
setTexParameter(textureObject, TEXTURE_MIN_FILTER, LINEAR)
OpenGL can't directly manipulate texture objects, to update/set their content, or change their parameters, you have to first bind them to the active texture unit (whichever it is). The equivalent code becomes :
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)
Shaders
Shaders have access to all the texture units, they don't care about the active texture.
Sampler uniforms are int
values representing the index of the texture unit to use for the sampler (and not the texture object to use).
So you have to bind your texture objects to the units you want to use.
The type of the sampler will do the match with the texture target that is used in the texture unit : Sampler2D
for GL_TEXTURE_2D
, and so on...
Imagine the GPU like some paint processing plant.
There are a number of tanks, which delivers dye to some painting machine. In the painting machine the dye is then applied to the object. Those tanks are the texture units
Those tanks can be equipped with different kinds of dye. Each kind of dye requires some other kind of solvent. The "solvent" is the texture target. For convenience each tank is connected to some solvent supply, and but only one kind of solvent can be used at a time in each tank. So there's a valve/switch TEXTURE_CUBE_MAP
, TEXTURE_3D
, TEXTURE_2D
, TEXTURE_1D
. You can fill all the dye types into the tank at the same time, but since only one kind of solvent goes in, it will "dilute" only the kind of dye matching. So you can have each kind of texture being bound, but the binding with the "most important" solvent will actually go into the tank and mix with the kind of dye it belongs to.
And then there's the dye itself, which comes from a warehouse and is filled into the tank by "binding" it. That's your texture.
If in your shader you need lookup from 2 textures:
uniform sampler2D tex1;
uniform sampler2D tex2;
it is necessary to indicate for tex1 and tex2 their sources as follows :
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");
in the render loop :
gl.uniform1i(tex1Loc, 3);
gl.uniform1i(tex2Loc, 7);
// but you can dynamically change these values
With a gl_bindtexture, not possible to do such a thing. On the other hand a possible use of a bind in the loop of rendering, is the case where you feed a texture with a content in stream (video, webcam) :
gl.bindTexture(gl.TEXTURE_2D, tex1);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, video);
// in the render loop
'Programming' 카테고리의 다른 글
VB.NET에서 인라인 목록 초기화 (0) | 2020.07.05 |
---|---|
Typescript의 ES6 맵 (0) | 2020.07.05 |
전체 HTML 양식을 "읽기 전용"으로 만들려면 어떻게해야합니까? (0) | 2020.07.04 |
ASP.NET MVC의 EditorFor ()에 대한 HTML 특성 (0) | 2020.07.04 |
OS X에서 sed를 사용한 전체 편집 (0) | 2020.07.04 |