Wie im nachfolgenden Beispiel gezeigt, erfolgt der Zugriff auf einen Texture Buffer in einem Shader-Programm mithilfe der texelFetch()-GLSL-Shaderfunktion:
uniform samplerBuffer SunInstancesTextureBuffer;
[...]
void main()
{
int Index = 4*gl_InstanceID;
mat4 matWorldViewProjection = mat4(texelFetch(SunInstancesTextureBuffer,
Index++),
texelFetch(SunInstancesTextureBuffer,
Index++),
texelFetch(SunInstancesTextureBuffer,
Index++),
texelFetch(SunInstancesTextureBuffer,
Index));
[...]
}
Die Übergabe eines Texture-Buffer-Objekts an einen Shader erfolgt in unseren Programmbeispielen mithilfe der CGLSLShader-Methode Set_TextureBuffer():
void CGLSLShader::Set_TextureBuffer(long Stage, CTexture* pTexture,
char* pParameter)
char* pParameter)
{
// Textur bereits gesetzt:
if(g_StageTexture[Stage] == pTexture)
return;
if(pTexture)
{
if(Stage > TextureStagesUsed)
TextureStagesUsed = Stage;
glActiveTexture(GL_TEXTURE0+Stage);
glBindTexture(GL_TEXTURE_BUFFER, pTexture->TextureID);
glUniform1i(glGetUniformLocation(ShaderProgram, pParameter), Stage);
}
g_StageTexture[Stage] = pTexture;
}
Für die praktische Handhabung dieser Buffer-Objekte nutzen wir ferner die CTextureBufferObject-Klasse unseres OpenGL/OpenCL-basierten Grafik- und Physik-Frameworks:
class CTextureBufferObject
{
public:
CTexture* Texture;
GLuint TextureBufferID;
long NumBufferElements;
long NumBufferElementsTU;
long NumBufferElementsTV;
CTextureBufferObject();
~CTextureBufferObject();
void Init_TextureBuffer(long numBufferElements, long numColorChannels,
float* pData = NULL);
void Init_TextureBuffer(long numBufferElementsTU,
long numBufferElementsTV,
long numColorChannels, float* pData = NULL);
void Update_Buffer(float* pData, long Size);
void Update_Buffer(float* pData, long Offset, long Size);
};
CTextureBufferObject::CTextureBufferObject()
{
Texture = NULL;
TextureBufferID = 0;
NumBufferElements = 0;
NumBufferElementsTU = 0;
NumBufferElementsTV = 0;
Texture = new CTexture;
}
CTextureBufferObject::~CTextureBufferObject()
{
if(TextureBufferID > 0)
glDeleteBuffers(1, &TextureBufferID);
SAFE_DELETE(Texture)
}
Im Rahmen der täglichen Arbeit stellt man sich einen Texture Buffer sinnvollerweise als eine Kombination aus einem eindimensionalen Textur- und einem separaten Buffer-Objekt vor (das Textur-Objekt verweist auf den Speicherbereich des Buffer-Objekts). Während der Zugriff auf die im Buffer gespeicherten Daten – wie im einleitenden Source-Code-Beispiel gezeigt – innerhalb eines Shader-Programms über ein der Textur zugeordnetes samplerBuffer-Objekt erfolgt, so ist der Zugriff auf die im Buffer gespeicherten Daten aus dem Hauptprogramm heraus auf direkte Weise möglich. Für die Aktualisierung dieser Daten können die beiden Update_Buffer()-Methoden der CTextureBufferObject-Klasse verwendet werden:
void CTextureBufferObject::Update_Buffer(float* pData, long Size)
{
glBindBuffer(GL_TEXTURE_BUFFER, TextureBufferID);
glBufferData(GL_TEXTURE_BUFFER, Size, pData, GL_STATIC_DRAW);
glBindBuffer(GL_TEXTURE_BUFFER, 0);
}
void CTextureBufferObject::Update_Buffer(float* pData, long Offset,
long Size)
{
glBindBuffer(GL_TEXTURE_BUFFER, TextureBufferID);
glBufferSubData(GL_TEXTURE_BUFFER, Offset, Size, pData);
glBindBuffer(GL_TEXTURE_BUFFER, 0);
}
Bevor nun ein Texture-Buffer-Objekt genutzt werden kann, sind die folgenden Initialisierungsschritte erforderlich:
- Initialisierung des Buffer-Objekts (TextureBufferID).
- Initialisierung des Textur-Objekts (TextureID).
- Anbinden des Buffer-Objekts an das Textur-Objekt.
void CTextureBufferObject::Init_TextureBuffer(long numBufferElementsTU,
long numBufferElementsTV, long numColorChannels, float* pData)
{
if(TextureBufferID > 0)
glDeleteBuffers(1, &TextureBufferID);
if(Texture->TextureID > 0)
glDeleteBuffers(1, &Texture->TextureID);
NumBufferElementsTU = numBufferElementsTU;
NumBufferElementsTV = numBufferElementsTV;
NumBufferElements = NumBufferElementsTU*NumBufferElementsTV;
// Buffer-Objekt initialisieren:
glGenBuffers(1, &TextureBufferID);
glBindBuffer(GL_TEXTURE_BUFFER, TextureBufferID);
unsigned long BufferSize;
if(numColorChannels == 4)
BufferSize = NumBufferElements * 4 * sizeof(float);
else if(numColorChannels == 3)
BufferSize = NumBufferElements * 3 * sizeof(float);
else if(numColorChannels == 2)
BufferSize = NumBufferElements * 2 * sizeof(float);
else
BufferSize = NumBufferElements * sizeof(float);
if(pData == NULL)
glBufferData(GL_TEXTURE_BUFFER, BufferSize, 0, GL_STATIC_DRAW);
else
glBufferData(GL_TEXTURE_BUFFER, BufferSize, pData, GL_STATIC_DRAW);
// Textur-Objekt initialisieren:
glGenTextures(1, &Texture->TextureID);
glBindTexture(GL_TEXTURE_BUFFER, Texture->TextureID);
// Buffer-Objekt an das Textur-Objekt anbinden:
if(numColorChannels == 4)
glTexBuffer(GL_TEXTURE_BUFFER, GL_RGBA32F, TextureBufferID);
else if(numColorChannels == 3)
glTexBuffer(GL_TEXTURE_BUFFER, GL_RGB32F, TextureBufferID);
else if(numColorChannels == 2)
glTexBuffer(GL_TEXTURE_BUFFER, GL_RG32F, TextureBufferID);
else
glTexBuffer(GL_TEXTURE_BUFFER, GL_R32F, TextureBufferID);
glBindTexture(GL_TEXTURE_BUFFER, 0);
glBindBuffer(GL_TEXTURE_BUFFER, 0);
}