C++ UBO不能与OpenGL 4一起正常工作

C++ UBO不能与OpenGL 4一起正常工作,c++,opengl,glsl,C++,Opengl,Glsl,我很难在我的项目中使用OpenGL 4.0+实现支持light数据 我尝试使用UBO存储预定义最大数量的灯光数据数组,并从片段着色器访问它 以下是着色器: #version 400 core in vec2 tCoord; smooth in vec4 vPosition; smooth in vec4 vNormal; // Diffuse texture. uniform sampler2D sTexture0; uniform vec4 vMatAmbientColor; unifo

我很难在我的项目中使用OpenGL 4.0+实现支持light数据

我尝试使用UBO存储预定义最大数量的灯光数据数组,并从片段着色器访问它

以下是着色器:

#version 400 core

in vec2 tCoord;
smooth in vec4 vPosition;
smooth in vec4 vNormal;

// Diffuse texture.
uniform sampler2D sTexture0;

uniform vec4 vMatAmbientColor;
uniform vec4 vMatDiffuseColor;
uniform vec4 vMatSpecularColor;

out vec4 fragColor;

struct LightData
{
    int Type;
    vec3 Position;
    vec3 Direction;
    float Radius;
    float Attenuation;
    float CutOffAngle;
    vec4 AmbientColor;
    vec4 DiffuseColor;
    vec4 SpecularColor;
};

#define MAX_LIGHTS_COUNT 32

layout ( std140 ) uniform LightsList
{
    LightData Light[MAX_LIGHTS_COUNT];
    int LightsCount;
} Lights;

vec4 calculateLighting( LightData _light )
{
    vec4 _result = vec4( 0.0 );
    if( _light.Type == 1 ) // directional
    {
        _result = ( _light.AmbientColor * vMatAmbientColor ) + ( _light.DiffuseColor * vMatDiffuseColor * vec4( texture( sTexture0, tCoord ).rgba ) ) + ( _light.SpecularColor * vMatSpecularColor );
    }
    else
    if( _light.Type == 2 ) // point
    {
        float _attenuation = 1.0 / ( 1.0 + _light.Attenuation * pow( distance( vec4( _light.Position.xyz, 1.0 ), vPosition ), 2 ) );
        _result = ( _light.AmbientColor * vMatAmbientColor ) + ( ( _light.DiffuseColor * vMatDiffuseColor * vec4( texture( sTexture0, tCoord ).rgba ) ) + ( _light.SpecularColor * vMatSpecularColor ) ) * _attenuation;
    }
    else
    if( _light.Type == 3 ) // spot
    {
        float _attenuation = 1.0 / ( 1.0 + _light.Attenuation * pow( distance( vec4( _light.Position.xyz, 1.0 ), vPosition ), 2 ) );
        _result = ( _light.AmbientColor * vMatAmbientColor ) + ( ( _light.DiffuseColor + vMatDiffuseColor * texture( sTexture0, tCoord ) ) + ( _light.SpecularColor * vMatSpecularColor ) ) * _attenuation;
    }
    return _result;
}

void main( void )
{
    fragColor = vec4( Lights.LightsCount );
    int i;
    for( i = 0; i < Lights.LightsCount; ++i )
    {
        fragColor += calculateLighting( Lights.Light[ i ] );
    }
}
C++,设置代码:

// Initialize light data storage.
if( m_iProgram && ( s_iLightDataBufferID == 0U ) )
{
    s_iLightDataBlockIndex = glGetUniformBlockIndex( m_iProgram, "LightsList" );
    glGetActiveUniformBlockiv( m_iProgram, s_iLightDataBlockIndex, GL_UNIFORM_BLOCK_DATA_SIZE, &s_iLightDataBufferSize );
    // Get indices for light data.
    glGetUniformIndices(
        m_iProgram,
        k_iLightsListMembersCount,
        k_sLightsListMemberNames,
        s_iLightsListMemberIndices
    );
    glGetUniformIndices(
        m_iProgram,
        k_iLightDataMembersCount,
        k_sLightDataMemberNames,
        s_iLightDataMemberIndices
    );
    if( s_iLightsListMemberIndices[ 0 ] != GL_INVALID_INDEX )
    {
        // Get offsets for members of LightsList.
        glGetActiveUniformsiv(
            m_iProgram,
            k_iLightsListMembersCount,
            s_iLightsListMemberIndices,
            GL_UNIFORM_OFFSET,
            s_iLightsListMemberOffsets
        );

        const GLchar* _lightsList2ndElementName[ 1 ] = { "LightsList.Light[1].Type" };
        GLuint _lightsList2ndElementIndex[ 1 ] = { GL_INVALID_INDEX };
        GLint _lightsList2ndElementOffset[ 1 ] = { 0 };
        glGetUniformIndices( m_iProgram, 1, _lightsList2ndElementName, _lightsList2ndElementIndex );
        glGetActiveUniformsiv( m_iProgram, 1, _lightsList2ndElementIndex, GL_UNIFORM_OFFSET, _lightsList2ndElementOffset );
        s_iLightsListArrayStride = _lightsList2ndElementOffset[ 0 ] - s_iLightsListMemberOffsets[ 0 ];

        glGetActiveUniformsiv(
            m_iProgram,
            k_iLightDataMembersCount,
            s_iLightDataMemberIndices,
            GL_UNIFORM_OFFSET,
            s_iLightDataMemberOffsets
        );
        // Create UBO.
        glGenBuffers( 1, &s_iLightDataBufferID );
        glBindBuffer( GL_UNIFORM_BUFFER, s_iLightDataBufferID );
        glBufferData( GL_UNIFORM_BUFFER, s_iLightDataBufferSize, nullptr, GL_DYNAMIC_DRAW );

        glUniformBlockBinding( m_iProgram, s_iLightDataBlockIndex, k_iLightDataUniformBlockBinding );
        // Bind data buffer to blocks.
        glBindBufferBase( GL_UNIFORM_BUFFER, k_iLightDataUniformBlockBinding, s_iLightDataBufferID );
        // Cleanup.
        glBindBuffer( GL_UNIFORM_BUFFER, 0 );
    }
}
注2:我计算数组步长的方法只是暂时的,之所以是这样,是因为目前我无法让glGetActiveUniformsiv()为Light[]数组正确返回数组步长。现在这并不重要

C++,每帧缓冲区更新:

if( s_iLightDataBufferID != 0U )
{
    // Establish binding and mapping.
    glBindBuffer( GL_UNIFORM_BUFFER, s_iLightDataBufferID );
    void* _map = glMapBuffer( GL_UNIFORM_BUFFER, GL_WRITE_ONLY );

    // Calculate and store lights count.
    unsigned int _lightsCount = 0;
    if( _maxCount == -1 )
    {
        _lightsCount = _lights.size();
    }
    else
    {
        _lightsCount = ( unsigned int )( _maxCount );
    }
    if( _lightsCount > k_iMaxAllowedLightSources )
    {
        _lightsCount = k_iMaxAllowedLightSources;
    }
    memcpy( _map + s_iLightsListMemberOffsets[ 1 ], &( _lightsCount ), sizeof( GLint ) );

    // Assemble lights data.
    for( unsigned int _lightIndex = 0; _lightIndex < _lightsCount; ++_lightIndex )
    {
        GLint _baseOffset = _lightIndex * s_iLightsListArrayStride;
        gizmo::scene::CGLightSceneObject* _nextLight = _lights[ _lightIndex ];
        // Type.
        GLint _type = _nextLight->getLightType();
        memcpy( _map + _baseOffset + s_iLightDataMemberOffsets[ 0 ], &( _type ), sizeof( GLint ) );
        // Position.
        irr::core::vector3df _position = _nextLight->getAbsolutePosition();
        memcpy( _map + _baseOffset + s_iLightDataMemberOffsets[ 1 ], &( _position.X ), sizeof( irr::core::vector3df ) );
        // Direction.
        irr::core::vector3df _direction = _nextLight->getAbsoluteRotation().rotationToDirection();
        memcpy( _map + _baseOffset + s_iLightDataMemberOffsets[ 2 ], &( _direction.X ), sizeof( irr::core::vector3df ) );
        // Radius.
        GLfloat _radius = _nextLight->getAbsoluteScale().X;
        memcpy( _map + _baseOffset + s_iLightDataMemberOffsets[ 3 ], &( _radius ), sizeof( GLfloat ) );
        // Attenuation.
        GLfloat _attenuation = _nextLight->getAttenuation();
        memcpy( _map + _baseOffset + s_iLightDataMemberOffsets[ 4 ], &( _attenuation ), sizeof( GLfloat ) );
        // Cut-off angle.
        GLfloat _cutOffAngle = irr::core::degToRad( _nextLight->getCutOffAngle() );
        memcpy( _map + _baseOffset + s_iLightDataMemberOffsets[ 5 ], &( _cutOffAngle ), sizeof( GLfloat ) );
        // Ambient color.
        GLfloat _ambientColor[ 4 ];
        _ambientColor[ 0 ] = _nextLight->getAmbientColor().getRed() / 255.0f;
        _ambientColor[ 1 ] = _nextLight->getAmbientColor().getGreen() / 255.0f;
        _ambientColor[ 2 ] = _nextLight->getAmbientColor().getBlue() / 255.0f;
        _ambientColor[ 3 ] = _nextLight->getAmbientColor().getAlpha() / 255.0f;
        memcpy( _map + _baseOffset + s_iLightDataMemberOffsets[ 6 ], &( _ambientColor ), 4 * sizeof( GLfloat ) );
        // Diffuse color.
        GLfloat _diffuseColor[ 4 ];
        _diffuseColor[ 0 ] = _nextLight->getDiffuseColor().getRed() / 255.0f;
        _diffuseColor[ 1 ] = _nextLight->getDiffuseColor().getGreen() / 255.0f;
        _diffuseColor[ 2 ] = _nextLight->getDiffuseColor().getBlue() / 255.0f;
        _diffuseColor[ 3 ] = _nextLight->getDiffuseColor().getAlpha() / 255.0f;
        memcpy( _map + _baseOffset + s_iLightDataMemberOffsets[ 7 ], &( _diffuseColor ), 4 * sizeof( GLfloat ) );
        // Specular color.
        GLfloat _specularColor[ 4 ];
        _specularColor[ 0 ] = _nextLight->getSpecularColor().getRed() / 255.0f;
        _specularColor[ 1 ] = _nextLight->getSpecularColor().getGreen() / 255.0f;
        _specularColor[ 2 ] = _nextLight->getSpecularColor().getBlue() / 255.0f;
        _specularColor[ 3 ] = _nextLight->getSpecularColor().getAlpha() / 255.0f;
        memcpy( _map + _baseOffset + s_iLightDataMemberOffsets[ 8 ], &( _specularColor ), 4 * sizeof( GLfloat ) );
    }

    // Clear binding.
    glUnmapBuffer( GL_UNIFORM_BUFFER );
    glBindBuffer( GL_UNIFORM_BUFFER, 0U );
}
如果没有照明,场景看起来很好(片段着色器中的simple texture()fetch)。但是,如果将1个灯光添加到场景中,并使用此着色器,则结果是黑屏。
此外,我已经验证了Lights.lightscont在着色器中等于0(似乎未初始化)。

什么是UBO?[[[[[[[[@cheers-sandhth.-Alf Uniform Buffer Object,我假设。一件事。是的,那是一个统一的缓冲区。所以你使用
std140
layout,但你仍然想手动查询偏移量。为什么呢?
std140
layout的关键是它是标准的,因此可以在所有硬件上预测。你不必查询任何东西。你可以签署一个C++结构,它与GLSL结构中的数据布局相匹配。该代码之所以存在是因为我在开发过程中只添加了STD140,但是,实际上,我打算使用共享布局,如果我设法修复它,在任何情况下,这都不是问题。
if( s_iLightDataBufferID != 0U )
{
    // Establish binding and mapping.
    glBindBuffer( GL_UNIFORM_BUFFER, s_iLightDataBufferID );
    void* _map = glMapBuffer( GL_UNIFORM_BUFFER, GL_WRITE_ONLY );

    // Calculate and store lights count.
    unsigned int _lightsCount = 0;
    if( _maxCount == -1 )
    {
        _lightsCount = _lights.size();
    }
    else
    {
        _lightsCount = ( unsigned int )( _maxCount );
    }
    if( _lightsCount > k_iMaxAllowedLightSources )
    {
        _lightsCount = k_iMaxAllowedLightSources;
    }
    memcpy( _map + s_iLightsListMemberOffsets[ 1 ], &( _lightsCount ), sizeof( GLint ) );

    // Assemble lights data.
    for( unsigned int _lightIndex = 0; _lightIndex < _lightsCount; ++_lightIndex )
    {
        GLint _baseOffset = _lightIndex * s_iLightsListArrayStride;
        gizmo::scene::CGLightSceneObject* _nextLight = _lights[ _lightIndex ];
        // Type.
        GLint _type = _nextLight->getLightType();
        memcpy( _map + _baseOffset + s_iLightDataMemberOffsets[ 0 ], &( _type ), sizeof( GLint ) );
        // Position.
        irr::core::vector3df _position = _nextLight->getAbsolutePosition();
        memcpy( _map + _baseOffset + s_iLightDataMemberOffsets[ 1 ], &( _position.X ), sizeof( irr::core::vector3df ) );
        // Direction.
        irr::core::vector3df _direction = _nextLight->getAbsoluteRotation().rotationToDirection();
        memcpy( _map + _baseOffset + s_iLightDataMemberOffsets[ 2 ], &( _direction.X ), sizeof( irr::core::vector3df ) );
        // Radius.
        GLfloat _radius = _nextLight->getAbsoluteScale().X;
        memcpy( _map + _baseOffset + s_iLightDataMemberOffsets[ 3 ], &( _radius ), sizeof( GLfloat ) );
        // Attenuation.
        GLfloat _attenuation = _nextLight->getAttenuation();
        memcpy( _map + _baseOffset + s_iLightDataMemberOffsets[ 4 ], &( _attenuation ), sizeof( GLfloat ) );
        // Cut-off angle.
        GLfloat _cutOffAngle = irr::core::degToRad( _nextLight->getCutOffAngle() );
        memcpy( _map + _baseOffset + s_iLightDataMemberOffsets[ 5 ], &( _cutOffAngle ), sizeof( GLfloat ) );
        // Ambient color.
        GLfloat _ambientColor[ 4 ];
        _ambientColor[ 0 ] = _nextLight->getAmbientColor().getRed() / 255.0f;
        _ambientColor[ 1 ] = _nextLight->getAmbientColor().getGreen() / 255.0f;
        _ambientColor[ 2 ] = _nextLight->getAmbientColor().getBlue() / 255.0f;
        _ambientColor[ 3 ] = _nextLight->getAmbientColor().getAlpha() / 255.0f;
        memcpy( _map + _baseOffset + s_iLightDataMemberOffsets[ 6 ], &( _ambientColor ), 4 * sizeof( GLfloat ) );
        // Diffuse color.
        GLfloat _diffuseColor[ 4 ];
        _diffuseColor[ 0 ] = _nextLight->getDiffuseColor().getRed() / 255.0f;
        _diffuseColor[ 1 ] = _nextLight->getDiffuseColor().getGreen() / 255.0f;
        _diffuseColor[ 2 ] = _nextLight->getDiffuseColor().getBlue() / 255.0f;
        _diffuseColor[ 3 ] = _nextLight->getDiffuseColor().getAlpha() / 255.0f;
        memcpy( _map + _baseOffset + s_iLightDataMemberOffsets[ 7 ], &( _diffuseColor ), 4 * sizeof( GLfloat ) );
        // Specular color.
        GLfloat _specularColor[ 4 ];
        _specularColor[ 0 ] = _nextLight->getSpecularColor().getRed() / 255.0f;
        _specularColor[ 1 ] = _nextLight->getSpecularColor().getGreen() / 255.0f;
        _specularColor[ 2 ] = _nextLight->getSpecularColor().getBlue() / 255.0f;
        _specularColor[ 3 ] = _nextLight->getSpecularColor().getAlpha() / 255.0f;
        memcpy( _map + _baseOffset + s_iLightDataMemberOffsets[ 8 ], &( _specularColor ), 4 * sizeof( GLfloat ) );
    }

    // Clear binding.
    glUnmapBuffer( GL_UNIFORM_BUFFER );
    glBindBuffer( GL_UNIFORM_BUFFER, 0U );
}
s_iLightsListMemberIndices[] = {8, 288};
s_iLightsListMemberOffsets[] = {0, 3584};
s_iLightDataMemberIndices[] = {8, 5, 4, 6, 1, 2, 0, 3, 7};
s_iLightDataMemberOffsets[] = {0, 16, 32, 44, 48, 52, 64, 80, 96};