Tudo sobre objetos OpenGL
O modelo padrão para objetos OpenGL é o seguinte.
Objetos têm estado. Pense neles como um struct
. Portanto, você pode ter um objeto definido assim:
struct Object
{
int count;
float opacity;
char *name;
};
O objeto possui certos valores armazenados e possui estado . Objetos OpenGL também têm estado.
Mudando de estado
No C / C ++, se você tiver uma instância do tipo Object
, altere seu estado da seguinte maneira: obj.count = 5;
Você faria referência direta a uma instância do objeto, obteria a parte específica do estado que deseja alterar e colocaria um valor nela.
No OpenGL, você não faz isso.
Por motivos legados, é melhor deixar inexplicável, para alterar o estado de um objeto OpenGL, você deve primeiro vinculá- lo ao contexto. Isso é feito com alguns de glBind*
chamada.
O equivalente em C / C ++ a isso é o seguinte:
Object *g_objs[MAX_LOCATIONS] = {NULL};
void BindObject(int loc, Object *obj)
{
g_objs[loc] = obj;
}
Texturas são interessantes; eles representam um caso especial de ligação. Muitas glBind*
chamadas têm um parâmetro "target". Isso representa diferentes locais no contexto do OpenGL em que objetos desse tipo podem ser vinculados. Por exemplo, você pode vincular um objeto buffer de moldura para leitura ( GL_READ_FRAMEBUFFER
) ou para gravação ( GL_DRAW_FRAMEBUFFER
). Isso afeta como o OpenGL usa o buffer. É isso que o loc
parâmetro acima representa.
Texturas são especiais porque quando você primeiro ligá-los a um alvo, que recebem informações especiais. Quando você liga uma textura pela primeira vez GL_TEXTURE_2D
, você está realmente definindo um estado especial na textura. Você está dizendo que essa textura é uma textura 2D. E sempre será uma textura 2D; esse estado não pode ser alterado nunca . Se você tem uma textura que foi primeiro vinculada como a GL_TEXTURE_2D
, sempre deve vinculá-la como a GL_TEXTURE_2D
; tentar vinculá-lo, pois GL_TEXTURE_1D
causará um erro (durante o tempo de execução).
Depois que o objeto é vinculado, seu estado pode ser alterado. Isso é feito através de funções genéricas específicas para esse objeto. Eles também usam um local que representa qual objeto modificar.
Em C / C ++, isso se parece com:
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;
}
}
Observe como esta função define o que quer que esteja no loc
valor atualmente vinculado .
Para objetos de textura, as principais funções de alteração do estado da textura são glTexParameter
. As únicas outras funções que alteram o estado da textura são as glTexImage
funções e suas variações ( glCompressedTexImage
, glCopyTexImage
recentes glTexStorage
). As várias SubImage
versões alteram o conteúdo da textura, mas tecnicamente não alteram seu estado . As Image
funções alocam armazenamento de textura e definem o formato da textura; as SubImage
funções apenas copiam pixels ao redor. Esse não é considerado o estado da textura.
Permita-me repetir: estas são as únicas funções que modificam o estado da textura. glTexEnv
modifica o estado do ambiente; isso não afeta nada armazenado em objetos de textura.
Textura ativa
A situação das texturas é mais complexa, mais uma vez por motivos legados, é melhor deixar de lado. É aqui que glActiveTexture
entra.
Para texturas, não são alvos apenas ( GL_TEXTURE_1D
, GL_TEXTURE_CUBE_MAP
, etc.). Existem também unidades de textura . Em termos de nosso exemplo de C / C ++, o que temos é o seguinte:
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;
}
Observe que agora não temos apenas uma lista 2D de Object
s, mas também temos o conceito de um objeto atual. Temos uma função para definir o objeto atual, temos o conceito de um número máximo de objetos atuais e todas as nossas funções de manipulação de objetos são ajustadas para selecionar o objeto atual.
Quando você altera o objeto ativo no momento, altera todo o conjunto de locais de destino. Portanto, você pode vincular algo que entra no objeto atual 0, alterna para o objeto atual 4 e modifica um objeto completamente diferente.
Essa analogia com objetos de textura é perfeita ... quase.
Veja, glActiveTexture
não leva um número inteiro; é preciso um enumerador . O que, em teoria, significa que pode levar qualquer coisa de GL_TEXTURE0
para GL_TEXTURE31
. Mas há uma coisa que você deve entender:
ISTO É FALSO!
O intervalo real que glActiveTexture
pode ser adotado é controlado por GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS
. Esse é o número máximo de multi-estruturas simultâneas que uma implementação permite. Cada um deles é dividido em diferentes agrupamentos para diferentes estágios do shader. Por exemplo, no hardware da classe GL 3.x, você obtém 16 texturas de shader de vértice, 16 de shader de fragmento e 16 de shaver de geometria. Portanto, GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS
será 48.
Mas não há 48 enumeradores. É por isso glActiveTexture
que realmente não recebe enumeradores. A maneira correta de ligar glActiveTexture
é a seguinte:
glActiveTexture(GL_TEXTURE0 + i);
onde i
é um número entre 0 e GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS
.
Renderização
Então, o que tudo isso tem a ver com renderização?
Ao usar shaders, você define os uniformes do amostrador para uma unidade de imagem de textura ( glUniform1i(samplerLoc, i)
, onde i
é a unidade de imagem). Isso representa o número com o qual você usou glActiveTexture
. O amostrador selecionará o alvo com base no tipo de amostrador. Então, um sampler2D
vai escolher a partir do GL_TEXTURE_2D
alvo. Essa é uma das razões pelas quais os amostradores têm tipos diferentes.
Agora, parece suspeito que você pode ter dois amostradores GLSL, com tipos diferentes que usam a mesma unidade de imagem de textura. Mas você não pode; O OpenGL proíbe isso e gera um erro quando você tenta renderizar.
GL_TEXTURE0 + i
- eu pretendia inspecionar os valores da enumeração para ver se isso era válido ou não. E o último parágrafo - não sabia se isso era legal ou não. Excelente! Estou marcando todas as suas respostas para que eu possa consultá-las novamente.