我在我的OpenGL/GLSL应用程序中实现了一个统一块,用于管理网格材质数据(环境光、漫反射光和镜面反射光以及反光)。
在我的第一次尝试中,我实现了以下统一块语法:
uniform MaterialBlock
{
vec3 Ka, Kd, Ks;
float Shininess;
};
以下是客户端代码:
scene::MaterialPtr pMaterial = this->FindMaterialByName(name);
GLuint bindingPoint = 0, bufferIndex = 0;
GLint blockSize = 0;
GLuint indices[4];
GLint offset[4];
const GLchar *names[4] = {"Ka", "Kd", "Ks", "Shininess" };
GLuint blockIndex = glGetUniformBlockIndex(this->m_Handle, "MaterialBlock");
glGetActiveUniformBlockiv(this->m_Handle, blockIndex, GL_UNIFORM_BLOCK_DATA_SIZE, &blockSize);
glGetUniformIndices(this->m_Handle, 4, names, indices);
glGetActiveUniformsiv(this->m_Handle, 4, indices, GL_UNIFORM_OFFSET, offset);
char *pBuffer = new char[blockSize];
memset(pBuffer, '\0', blockSize);
glm::vec3 ambient = pMaterial->GetAmbient();
glm::vec3 diffuse = pMaterial->GetDiffuse();
glm::vec3 specular = pMaterial->GetSpecular();
float shininess = pMaterial->GetShininess();
std::copy(reinterpret_cast<char*>(&ambient[0]),
reinterpret_cast<char*>(&ambient[0]) + sizeof(glm::vec4), pBuffer + offset[0]);
std::copy(reinterpret_cast<char*>(&diffuse[0]), reinterpret_cast<char*>(
&diffuse[0]) + sizeof(glm::vec4), pBuffer + offset[1]);
std::copy(reinterpret_cast<char*>(&specular[0]),
reinterpret_cast<char*>(&specular[0]) + sizeof(glm::vec3), pBuffer + offset[2]);
std::copy(reinterpret_cast<char*>(&shininess), reinterpret_cast<char*>(
&shininess) + sizeof(float), pBuffer + offset[3]);
glUniformBlockBinding(this->m_Handle, blockIndex, bindingPoint);
{
glGenBuffers(1, &bufferIndex);
glBindBuffer(GL_UNIFORM_BUFFER, bufferIndex);
{
glBufferData(GL_UNIFORM_BUFFER, blockSize, NULL, GL_DYNAMIC_DRAW);
glBufferSubData(GL_UNIFORM_BUFFER, 0, blockSize, (const GLvoid *)pBuffer);
}
glBindBuffer(GL_UNIFORM_BUFFER, 0);
}
glBindBufferBase(GL_UNIFORM_BUFFER, bindingPoint, bufferIndex);
//TEXTURE.
{
this->SetUniform("colorSampler", 0); //THE CHANNEL HAS TO BE CALCULATED! //int
glActiveTexture(GL_TEXTURE0); //DYNAMICS.
pMaterial->GetTexture()->Lock();
}
变量内容:
blockIndex: 0 //OK
blockSize: 48 //OK
Indices: {1, 2, 3, 78} //OK
Offset: {0, 16, 32, 44} //OK
片段着色器代码:
#version 440
#define MAX_LIGHT_COUNT 10
/*
** Output color value.
*/
layout (location = 0) out vec4 FragColor;
/*
** Inputs.
*/
in vec3 Position;
in vec2 TexCoords;
in vec3 Normal;
/*
** Material uniform block.
*/
uniform MaterialBlock
{
vec3 Ka, Kd, Ks;
float Shininess;
};
uniform sampler2D ColorSampler;
struct Light
{
vec4 Position;
vec3 La, Ld, Ls;
float Kc, Kl, Kq;
};
uniform struct Light LightInfos[MAX_LIGHT_COUNT];
uniform unsigned int LightCount;
/*
** Light attenuation factor.
*/
float getLightAttenuationFactor(vec3 lightDir, Light light)
{
float lightAtt = 0.0f;
float dist = 0.0f;
dist = length(lightDir);
lightAtt = 1.0f / (light.Kc + (light.Kl * dist) + (light.Kq * pow(dist, 2)));
return (lightAtt);
}
/*
** Basic phong shading.
*/
vec3 Basic_Phong_Shading(vec3 normalDir, vec3 lightDir, vec3 viewDir, int idx)
{
vec3 Specular = vec3(0.0f);
float lambertTerm = max(dot(lightDir, normalDir), 0.0f);
vec3 Ambient = LightInfos[idx].La * Ka;
vec3 Diffuse = LightInfos[idx].Ld * Kd * lambertTerm;
if (lambertTerm > 0.0f)
{
vec3 reflectDir = reflect(-lightDir, normalDir);
Specular = LightInfos[idx].Ls * Ks * pow(max(dot(reflectDir, viewDir), 0.0f), Shininess);
}
return (Ambient + Diffuse + Specular);
}
/*
** Fragment shader entry point.
*/
void main(void)
{
vec3 LightIntensity = vec3(0.0f);
vec4 texDiffuseColor = texture2D(ColorSampler, TexCoords);
vec3 normalDir = (gl_FrontFacing ? -Normal : Normal);
for (int idx = 0; idx < LightCount; idx++)
{
vec3 lightDir = vec3(LightInfos[idx].Position) - Position.xyz;
vec3 viewDir = -Position.xyz;
float lightAttenuationFactor = getLightAttenuationFactor(lightDir, LightInfos[idx]);
LightIntensity += Basic_Phong_Shading(
-normalize(normalDir), normalize(lightDir), normalize(viewDir), idx
) * lightAttenuationFactor;
}
FragColor = vec4(LightIntensity, 1.0f) * texDiffuseColor;
}
这段代码工作得很好。输出如下:
但我知道,可以将实例名(如C/C++中的结构)与统一块一起使用,如下所示:
uniform MaterialBlock
{
vec3 Ka, Kd, Ks;
float Shininess;
} MaterialInfos;
当然,着色器中使用的所有变量,如“Ka”、“Kd”、“Ks”和“shinity”,都会变成“materialinfo”。《物质信息》。Kd’,“材料信息”。“Ks”和“MaterialInfo”。“光亮”。
但不幸的是,程序执行失败,因为在客户机代码中,varibales的“索引”和“偏移”没有正确填充。
这是日志:
blockIndex: 0 //OK
blockSize: 48 //OK
Indices: {4294967295, 4294967295, 4294967295, 4294967295} //NOT OK
Offset: {-858993460, -858993460, -858993460, -858993460} //NOT OK
因此,只有块索引和块大小是正确的。因此,为了解决问题,我尝试更改行:
const GLchar *names[4] = {"Ka", "Kd", "Ks", "Shininess" };
const GLchar *names[4] = {"MaterialInfos.Ka", "MaterialInfos.Kd", "MaterialInfos.Ks", "MaterialInfos.Shininess" };
但是对于变量'index'和'offset',我仍然有相同的日志。因此,我的申请仍然失败。我认为这是客户端代码中的语法问题(不是GLSL代码,因为我没有GLSL错误),但我找不到解决方案。
你知道我的问题来自哪里吗?