使用OpenGL/GLSL时,带有统一块(UBO)的实例名称不起作用 [英] Instance name with Uniform blocks (UBO) does not work using OpenGL/GLSL

查看:36
本文介绍了使用OpenGL/GLSL时,带有统一块(UBO)的实例名称不起作用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经在我的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, '', 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’和‘Shinness’都变成了‘MaterialInfos.Ka’、‘MaterialInfos.Kd’、‘MaterialInfos.Ks’和‘MaterialInfos.Shinness’。

但不幸的是,程序执行失败,因为在客户端代码中,上面的变量"index"和"Offset"未正确填充。

日志如下:

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错误),但是我找不到解决方案。

您知道我的问题来自哪里吗?

推荐答案

使用实例化统一块时,OpenGL application uses the block name (in this case MaterialBlock) before the dot,而不是当前代码中的实例名称。实例名称仅由GLSL着色器可见。

因此,您的names变量应该这样定义和初始化:

const GLchar *names[4] = {"MaterialBlock.Ka", "MaterialBlock.Kd", "MaterialBlock.Ks", "MaterialBlock.Shininess" };

这篇关于使用OpenGL/GLSL时,带有统一块(UBO)的实例名称不起作用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆