UBO无法与OpenGL 4

时间:2016-04-01 11:08:05

标签: c++ opengl glsl

使用OpenGL 4.0 +,我很难在项目中使用UBO支持实现轻量数据。

我正在尝试使用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 ] );
    }
}

注意:没关系在calculateLighting()中的代码,现在它是一个虚拟代码,但它应该提供至少任何计算和返回的结果的最小结果。

在C ++中,我定义了这样的字段名称:

const GLchar* k_sLightsListMemberNames[ 2 ] =
{
    "LightsList.Light[0].Type",
    "LightsList.LightsCount"
};
const GLchar* k_sLightDataMemberNames[ 9 ] =
{
    "LightsList.Light[0].Type",
    "LightsList.Light[0].Position",
    "LightsList.Light[0].Direction",
    "LightsList.Light[0].Radius",
    "LightsList.Light[0].Attenuation",
    "LightsList.Light[0].CutOffAngle",
    "LightsList.Light[0].AmbientColor",
    "LightsList.Light[0].DiffuseColor",
    "LightsList.Light[0].SpecularColor"
};

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 );
}

在渲染过程中,我只是将VAO与相关的顶点和索引缓冲区绑定,并在GL_TRIANGLE_STRIP模式下使用glDrawElements()简单地绘制几何体。

检索到的块索引和偏移看起来像OK:

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};

没有光照,场景看起来很好(片段着色器中的简单纹理()获取)。但是,在场景中添加了1个灯光,并且使用了此着色器,结果为黑屏。 此外,我已经在着色器中验证Lights.LightsCount等于0(看起来像是非初始化的)。

0 个答案:

没有答案