Issue with native render using OpenGL 4.+/ GLSL 4+

You are an experienced programmer and have a problem with the engine, shaders, or advanced effects? Here you'll get answers.
No questions about C++ programming or topics which are answered in the tutorials!
Post Reply
Jack_the_Forceman
Posts: 10
Joined: Thu Jan 26, 2012 1:02 am

Issue with native render using OpenGL 4.+/ GLSL 4+

Post by Jack_the_Forceman »

Hello, guys.

I've been writing my own OpengGL renderer for my own engine, built atop of Irrlicht. I went with using CMesh/CAnimatedMesh/CSkinnedMesh implementations, using raw data out of then in order to construct OpenGL data that is fed to VBOs and consequentially bound to VAO.
Then I simply render desired object through glDrawArrays(), with appropriate VAO bound.
However, I get some bizarre stuff as a result - vertices data for mesh gets completely messed up, resulting in a jagged set of rendered triangles that only seemingly look like the original mesh from afar.
OpenGL EXT wrapper that I'm using is GLFW/GL3W, the one that comes with OpenGL SuperBible source code - I'm properly calling gl3wInit() on the first call to OpenGL functionality, so everything is initialized fine.

Some code to clear things out:

0) CGRenderSourceData class declaration (cpp file contains only constructor and destructor):

Code: Select all

 
        class CGRenderSourceData
        {
                friend class IGMaterialRenderer;
#ifdef _BUILD_WITH_OPENGL_3_
                friend class CGOpenGL3MaterialRenderer;
#endif // _BUILD_WITH_OPENGL_3_
#ifdef _BUILD_WITH_OPENGL_4_
                friend class CGOpenGL4MaterialRenderer;
#endif // _BUILD_WITH_OPENGL_4_
#ifdef _BUILD_WITH_OPENGL_ES_2_
                friend class CGOpenGLES2MaterialRenderer;
#endif // _BUILD_WITH_OPENGL_ES_2_
#ifdef _BUILD_WITH_OPENGL_ES_3_
                friend class CGOpenGLES3MaterialRenderer;
#endif // _BUILD_WITH_OPENGL_ES_3_
#ifdef _BUILD_WITH_D3D_9_
                friend class CGD3D9MaterialRenderer;
#endif // _BUILD_WITH_D3D_9_
#ifdef _BUILD_WITH_D3D_11_
                friend class CGD3D11MaterialRenderer;
#endif // _BUILD_WITH_D3D_11_
 
            private: /// CONSTRUCTION.
 
                CGRenderSourceData();
 
                ~CGRenderSourceData();
 
                // Disallow copy functionality.
                CLASS_PROHIBIT_COPYING( CGRenderSourceData );
 
            private: /// DATA
 
                // Core for the render pipeline (is used as VAO in OpenGL, stream source for D3D, and so on).
                DEFINE_CLASS_POINTER_RO( void, VertexHandleObject );
 
                // Size of vertex element.
                DEFINE_CLASS_PROPERTY_RO( size_t, i, VertexSize, 0 );
                // Used as static/dynamic GPU-side data buffer for vertex data.
                DEFINE_CLASS_POINTER_RO( void, VertexBuffer );
                // Amount of vertices being stored.
                DEFINE_CLASS_PROPERTY_RO( unsigned int, i, VertexCount, 0U );
                // Shortcut to vertices, stored within mesh.
                DEFINE_CLASS_POINTER_RO( void, Vertices );
 
                // Size of index element.
                DEFINE_CLASS_PROPERTY_RO( size_t, i, IndexSize, 0 );
                // GAPI-specific index type.
                DEFINE_CLASS_PROPERTY_RO( int, i, IndexType, 0 );
                // Used as static GPU-side data buffer for vertex indexing during render.
                DEFINE_CLASS_POINTER_RO( void, IndexBuffer );
                // Amount of indices being stored.
                DEFINE_CLASS_PROPERTY_RO( unsigned int, i, IndexCount, 0U );
                // Shortcut to indices, stored within mesh.
                DEFINE_CLASS_POINTER_RO( void, Indices );
        };
 
1) Initialize GL data from IMeshBuffer's content:

Code: Select all

 
CGRenderSourceData* CGOpenGL4MaterialRenderer::createRenderSourceData( irr::video::E_VERTEX_TYPE _vertexType, void* _vertexData, unsigned int _verticesCount, irr::video::E_INDEX_TYPE _indexType, void* _indexData, unsigned int _indicesCount, bool _animated )
{
    CGRenderSourceData* _newRenderSourceData = new CGRenderSourceData();
 
    GLuint _vao = 0;
    GLuint _buffers[ 2 ];
 
    // Create VAO.
    glGenVertexArrays( 1, &_vao );
    _newRenderSourceData->m_pVertexHandleObject = reinterpret_cast< void* >( _vao ); // Store VAO as vertex handle object.
    // Generate buffers for vertex and index data.
    glGenBuffers( 2, _buffers );
    _newRenderSourceData->m_pVertexBuffer = reinterpret_cast< void* >( _buffers[ 0 ] ); // Store vertex buffer.
    _newRenderSourceData->m_pIndexBuffer = reinterpret_cast< void* >( _buffers[ 1 ] ); // Store index buffer.
 
    resetRenderSourceData( _newRenderSourceData, _vertexType, _vertexData, _verticesCount, _indexType, _indexData, _indicesCount, _animated );
 
    // Return resulting object.
    return _newRenderSourceData;
}
// --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
void CGOpenGL4MaterialRenderer::resetRenderSourceData( CGRenderSourceData* _data, irr::video::E_VERTEX_TYPE _vertexType, void* _vertexData, unsigned int _verticesCount, irr::video::E_INDEX_TYPE _indexType, void* _indexData, unsigned int _indicesCount, bool _animated )
{
    if( _data )
    {
        // Get actual data handles.
        GLuint _vao = reinterpret_cast< GLuint >( _data->m_pVertexHandleObject );
        GLuint _buffers[ 2 ];
        _buffers[ 0 ] = reinterpret_cast< GLuint >( _data->m_pVertexBuffer );
        _buffers[ 1 ] = reinterpret_cast< GLuint >( _data->m_pIndexBuffer );
 
        // Bind VAO.
        glBindVertexArray( _vao );
 
        // Configure buffer for vertex data.
        glBindBuffer( GL_ARRAY_BUFFER, _buffers[ 0 ] );
        size_t _bufferSize = 0;
        _data->m_iVertexSize = getVertexPitchFromType( _vertexType );
        _bufferSize = _data->m_iVertexSize * _verticesCount;
 
        unsigned char* _vertexBuffer = new unsigned char[ _bufferSize + 1 ];
        memcpy( _vertexBuffer, _vertexData, _bufferSize );
        *( _vertexBuffer + _bufferSize ) = '\0';
 
        GLenum _vertexDataUsage = 0;
        if( _animated )
        {
            _vertexDataUsage = GL_DYNAMIC_DRAW;
        }
        else
        {
            _vertexDataUsage = GL_STATIC_DRAW;
        }
        // Fill buffer with vertex data.
        glBufferData( GL_ARRAY_BUFFER, _bufferSize, _vertexBuffer, _vertexDataUsage );
        // Define attributes.
        switch( _vertexType )
        {
            case irr::video::EVT_STANDARD:
            {
                // 1st attribute - position.
                glEnableVertexAttribArray( 0 );
                glVertexAttribPointer( 0, 3, GL_FLOAT, GL_FALSE, sizeof( irr::video::S3DVertex ), (void*)offsetof( irr::video::S3DVertex, Pos ) );
                // 2nd attribute - normal.
                glEnableVertexAttribArray( 1 );
                glVertexAttribPointer( 1, 3, GL_FLOAT, GL_FALSE, sizeof( irr::video::S3DVertex ), (void*)offsetof( irr::video::S3DVertex, Normal ) );
                // 3rd attribute - color.
                glEnableVertexAttribArray( 2 );
                glVertexAttribPointer( 2, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof( irr::video::S3DVertex ), (void*)offsetof( irr::video::S3DVertex, Color ) );
                // 4th attribute - texcoords.
                glEnableVertexAttribArray( 3 );
                glVertexAttribPointer( 3, 2, GL_FLOAT, GL_FALSE, sizeof( irr::video::S3DVertex ), (void*)offsetof( irr::video::S3DVertex, TCoords ) );
            }   break;
 
            /// other vertex types ..................
 
            default:
            {
                ASSERT( false, "[ CGOpenGL4MaterialRenderer::resetRenderSourceData() ] Unknown vertex type." );
            }   break;
        }
        _data->m_pVertices = _vertexData;
        glBindBuffer( GL_ARRAY_BUFFER, 0 );
        NULLIFY_PTR( _vertexBuffer );
 
        // Configure buffer for index data.
        glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, _buffers[ 1 ] );
        switch( _indexType )
        {
            case irr::video::EIT_16BIT:
            {
                _data->m_iIndexSize = sizeof( irr::u16 );
                _data->m_iIndexType = GL_UNSIGNED_SHORT;
            }   break;
            case irr::video::EIT_32BIT:
            {
                _data->m_iIndexSize = sizeof( irr::u32 );
                _data->m_iIndexType = GL_UNSIGNED_INT;
            }   break;
            default:
            {
                ASSERT( false, "[ CGOpenGL4MaterialRenderer::resetRenderSourceData() ] Unknown index type." );
                _data->m_iIndexSize = 0;
            }   break;
        }
        _bufferSize = _data->m_iIndexSize * _indicesCount;
        // Fill buffer with index data.
        glBufferData( GL_ELEMENT_ARRAY_BUFFER, _bufferSize, _indexData, GL_STATIC_DRAW );
        _data->m_pIndices = _indexData;
        glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, 0 );
 
        // Clear bound VAO points.
        glBindVertexArray( 0 );
 
        // Store vertices and indices counters.
        _data->m_iVertexCount = _verticesCount;
        _data->m_iIndexCount = _indicesCount;
    }
}
 
2) Render the source data ( vector of sources represents all mesh buffers of 1 single mesh )

Code: Select all

 
void CGOpenGL4MaterialRenderer::renderSourceData( const std::vector< CGRenderSourceData* > _data )
{
    if( !_data.empty() )
    {
        GLenum _mode = GL_TRIANGLES;
        gizmo::E_SCENE_OBJECT_RENDER_MODE _renderMode = gizmo::ESORM_TRIANGLES;
        if( m_pActiveMaterialInstance )
        {
            // Determine corresponding OpenGL render mode.
            _renderMode = m_pActiveMaterialInstance->getRenderMode();
            switch ( _renderMode )
            {
                case gizmo::ESORM_POINTS:
                {
                    _mode = GL_POINTS;
                }   break;
 
                case gizmo::ESORM_LINE_STRIP:
                {
                    _mode = GL_LINE_STRIP;
                }   break;
 
                case gizmo::ESORM_LINE_LOOP:
                {
                    _mode = GL_LINE_LOOP;
                }   break;
 
                case gizmo::ESORM_LINES:
                {
                    _mode = GL_LINES;
                }   break;
 
                case gizmo::ESORM_TRIANGLE_STRIP:
                {
                    _mode = GL_TRIANGLE_STRIP;
                }   break;
 
                case gizmo::ESORM_TRIANGLE_FAN:
                {
                    _mode = GL_TRIANGLE_FAN;
                }   break;
 
                case gizmo::ESORM_TRIANGLES:
                {
                    _mode = GL_TRIANGLES;
                }   break;
 
                default:
                {
                    ASSERT( false, "[ CGOpenGL4MaterialRenderer::renderSourceData() ] Unhandled render mode: %d.", ( int )( m_pActiveMaterialInstance->getRenderMode() ) );
                    _mode = GL_TRIANGLES;
                }   break;
            }
            // Setup back face render mode.
            if( m_pActiveMaterialInstance->isRenderBackFace() )
            {
                glDisable( GL_CULL_FACE );
            }
            else
            {
                glEnable( GL_CULL_FACE );
                glCullFace( GL_BACK );
            }
            // Bind textures.
            for( unsigned int i = 0; i < gizmo::k_iMaxBoundMaterialTexturesCount; ++i )
            {
                int _constantID = m_pActiveMaterialInstance->getTextureLayer( i )->getConstantID();
                GLuint _textureID = m_pActiveMaterialInstance->getTextureLayer( i )->getIntData()[ 0 ];
                if( ( _constantID != -1 ) && ( _textureID != 0 ) )
                {
                    glActiveTexture( GL_TEXTURE0 + i );
                    glBindTexture( GL_TEXTURE_2D, _textureID );
                    glUniform1i( _constantID, i );
                }
            }
        }
 
        glFrontFace( GL_CCW );
 
        for( unsigned int i = 0, n = _data.size(); i < n; ++i )
        {
            GLuint _vao = reinterpret_cast< GLuint >( _data[ i ]->m_pVertexHandleObject );
 
            // Bind VAO and index buffer.
            glBindVertexArray( _vao );
 
            // Issue draw command.
            glDrawArrays( _mode, 0, _data[ i ]->m_iIndexCount );
 
            irr::core::stringc _lastError = getLastError();
            if( !_lastError.empty() )
            {
                LOG( "GLSL", bullhorn::log::ELL_ERROR, "[ CGOpenGL4MaterialRenderer::renderSourceData() ] Error occured: %s.", _lastError.c_str() );
            }
        }
 
        // Clear state data.
        glDisable( GL_CULL_FACE );
        glBindVertexArray( 0 );
    }
 
3) How data creation process is used:

Code: Select all

 
void CGMeshSceneObject::initializeMesh( irr::scene::IAnimatedMesh* _mesh, bool _animated )
{
    m_bAnimated = _animated;
    gizmo::render::IGMaterialRenderer* _renderer = gizmo::macros::SCENE_MANAGER()->getDefaultMaterialRenderer();
    if( _mesh && _renderer )
    {
        // Reset mesh normals.
        gizmo::macros::IRRLICHT_SCENE_MANAGER()->getMeshManipulator()->recalculateNormals( _mesh, true, true );
        // Create per-buffer render data.
        for( unsigned int i = 0, n = _mesh->getMeshBufferCount(); i < n; ++i )
        {
            irr::scene::IMeshBuffer* _meshBuffer = _mesh->getMeshBuffer( i );
            irr::video::E_VERTEX_TYPE _vertexType = _meshBuffer->getVertexType();
            void* _vertexData = _meshBuffer->getVertices();
            unsigned int _vertexCount = _meshBuffer->getVertexCount();
            irr::video::E_INDEX_TYPE _indexType = _meshBuffer->getIndexType();
            void* _indexData = _meshBuffer->getVertices();
            unsigned int _indexCount = _meshBuffer->getIndexCount();
            gizmo::render::CGRenderSourceData* _newRenderSourceData = _renderer->createRenderSourceData( _vertexType, _vertexData, _vertexCount, _indexType, _indexData, _indexCount, _animated );
            m_oRenderSourceData.push_back( _newRenderSourceData );
        }
        m_pMesh = static_cast< irr::scene::ISkinnedMesh* >( _mesh );
    }
}
 
4) Default shaders that are used for test.
VS

Code: Select all

 
#version 400 core
 
layout ( location = 0 ) in vec3 position;
layout ( location = 1 ) in vec3 normal;
layout ( location = 2 ) in vec4 color;
layout ( location = 3 ) in vec2 texcoord;
 
uniform mat4 mWorldTransform;
uniform mat4 mViewTransform;
uniform mat4 mProjTransform;
 
out vec2 tCoord;
out vec4 tColor;
 
void main( void )
{
    gl_Position = mProjTransform * mViewTransform * mWorldTransform * vec4( position.xyz, 1 );
    tCoord = texcoord;
    tColor = color;
}
 
FS

Code: Select all

 
#version 400 core
 
in vec2 tCoord;
in vec4 tColor;
 
uniform sampler2D sTexture0;
 
out vec4 fragColor;
 
void main( void )
{
    fragColor = texture( sTexture0, tCoord );
}
 
On a "dwarf.x" mesh that comes along with irrlicht package, this code produces such results:


Render mode: GL_TRIANGLES
Image
Image
Image

Render mode: GL_TRIANGLE_STRIP
Image
Image
Image

Render mode: GL_LINES
Image
Image
Image

As you can see from the screenshots, each mode, more or less, has lots of triangles either messed up or completely absent.

Further clarification points:
1 ) Shaders I'm writing are compiled/linked/applied just fine.
2 ) Render process does not output any errors. That's why i'm completely clueless what's going on.
3 ) When glEnable( GL_DEPTH_TEST ) is applied before glDrawArrays() commands, the screen becomes completely black - note that original Irrlicht's COpenGLDriver is properly initialized on createDeviceEx(), with DepthBuffer bit enabled.
4 ) When glIsEnabled( GL_DEPTH_TEST ) is applied at the same time ( without calling glEnable() ), the result is GL_FALSE (presumably because of some 2D drawing the engine is performing using COpenGLDriver's functionality, like draw2DImage()).
5 ) Without glFrontFace ( GL_CCW ) call mesh is even more trashed, but I suspect that it's not the case here (but I'm wondering why it's GL_CW at the beginning - that's not OpenGL standard).
6 ) If glDrawElements() is called with index buffer ignored and mesh buffer's indices data supplied instead, the output is just 1 triangle that's not even amongst the triangles that form the original mesh buffer.
7 ) Mesh is loaded through IGSceneManager::getMesh() - no special magic is used for mesh creation, it's used for OpenGL data creation straight out-of-the-box.
8 ) Transformation matrices are properly applied before renderSourceData() method is called - actually, these screens are taked from the sample app that has a camera rotated around the mesh, and it works correct.
9 ) When any mesh is drawn, any GUI after this is not drawn - it's as it wasn't drawn at all. That's also a point of interest for me, but I suspect that it will fix itself once I re-write GUI to use GL 4+ renderer as well.
10 ) Mesh is not animated here, so data is set for VBO only once, upon creation - no further data copying is made after that (for now).

I suspect that it's probably an issue with the filling process of either VBO, or vertex attribute pointers - or even both of them.

I'm in desperate need of solving this issue, so any heads-up will be very much appreciated.
Thanks on advance.
mongoose7
Posts: 1227
Joined: Wed Apr 06, 2011 12:13 pm

Re: Issue with native render using OpenGL 4.+/ GLSL 4+

Post by mongoose7 »

I can't understand why you would want to do this. Have you heard of OpenGL?

Anyway, clearly your vertices are correct. It is most likely your indices. What about trying it with just a triangle or two?
Jack_the_Forceman
Posts: 10
Joined: Thu Jan 26, 2012 1:02 am

Re: Issue with native render using OpenGL 4.+/ GLSL 4+

Post by Jack_the_Forceman »

mongoose7 wrote:I can't understand why you would want to do this. Have you heard of OpenGL?
Um... wait wut ? :) Ofcourse I've heard about it, I'm actually writing for it! :) Or maybe you've meant something else?
Well, I really need a custom renderer, irrlicht's one just doesn't fit in my case, as I further need to write renderers for mantle, ES 3.0, and so on - and I need them now, so waiting for implementation on Irrlicht's side isn't an option for me.
mongoose7 wrote:Anyway, clearly your vertices are correct. It is most likely your indices. What about trying it with just a triangle or two?
Before going any further, it's worth mentioning that I've explicitly used a mesh that has (presumably) correct set of indices - dwarf is a mesh that comes with the package, so it has been tested bazillions of times, isn't it?

In any case, I've set up the cube using IGSceneManager's GeometryCreator, again to ensure that everying is perfect with the incoming data:

Code: Select all

 
    // Debug mesh.
    float _cubeSize = 1.0f;
    irr::scene::IMesh* _mesh = m_pSceneManager->getGeometryCreator()->createCubeMesh( core::vector3df( _cubeSize, _cubeSize, _cubeSize ) );
    _tempMesh->setMesh( _mesh );
 
Notes:
1) This cube model uses indices duplication, so such a setup is for GL_TRIANGLES render mode, not for GL_TRIANGLE_STRIP.
2) Winding is clock-wise, so I've changed glFrontFace( GL_CCW ) to glFrontFace( GL_CW ) in renderer's code.
3) The rest of the code, provided in previous post, is completely untouched.

And this is the output:

Render mode: GL_TRIANGLES:
Image
Image
Image

Render mode: GL_LINES:
Image
Image
Image

Also, when rendering only 1st tiangle:

Render mode: GL_TRIANGLES ( 1 triangle = 3 first indices ):
Image
Image

Render mode: GL_TRIANGLES ( 2 triangles = 6 first indices ):
Image
Image

Render mode: GL_LINES ( actually, 3 lines = 6 indices drawn):
Image
Image
Image

2 things that I've realized just now:
1) Cube is drawn inwards, so I guess that either normals are badly recalculated (I use getMeshManipulator()->recalculateNormals() when setting the mesh before creation of GL RenderData), or I really should go with GL_CCW winding order. Ofcorse, it may also be a bad vertex data that is fed to GL - I still can't identify this, because of the original issue.
2) In lines mode, I can really see that indices are used with incorrect order, while the vertices data is seemingly correct.
mongoose7
Posts: 1227
Joined: Wed Apr 06, 2011 12:13 pm

Re: Issue with native render using OpenGL 4.+/ GLSL 4+

Post by mongoose7 »

So your indices are not correct?
Jack_the_Forceman
Posts: 10
Joined: Thu Jan 26, 2012 1:02 am

Re: Issue with native render using OpenGL 4.+/ GLSL 4+

Post by Jack_the_Forceman »

Yep. And even more...
I have found that it's not simply incorrect - the order is actually ignored, and incides go as they would be picked straight from the order of actual vertices.
I've tried to render the cube in GL_LINES mode by adding 2 ponts step by step - when I've made it to 8 vertices, I've seen a full cube:

Image

And this is the cube definition graph from CCubeSceneNode.cpp:

Code: Select all

 
    /*
        011         111
          /6,8------/5        y
         /  |      / |        ^  z
        /   |     /  |        | /
    010 3,9-------2  |        |/
        |   7- - -10,4 101     *---->x
        |  /      |  /
        |/        | /
        0------11,1/
       000       100
    */
 
Finally, this is the mesh creation process (from CGeometryCreator.cpp):

Code: Select all

 
IMesh* CGeometryCreator::createCubeMesh(const core::vector3df& size) const
{
    SMeshBuffer* buffer = new SMeshBuffer();
 
    // Create indices
    const u16 u[36] = {   0,2,1,   0,3,2,   1,5,4,   1,2,5,   4,6,7,   4,5,6,
            7,3,0,   7,6,3,   9,5,2,   9,8,5,   0,11,10,   0,10,7};
 
    buffer->Indices.set_used(36);
 
    for (u32 i=0; i<36; ++i)
        buffer->Indices[i] = u[i];
 
 
    // Create vertices
    video::SColor clr(255,255,255,255);
 
    buffer->Vertices.reallocate(12);
 
    buffer->Vertices.push_back(video::S3DVertex(0,0,0, -1,-1,-1, clr, 0, 1));
    buffer->Vertices.push_back(video::S3DVertex(1,0,0,  1,-1,-1, clr, 1, 1));
    buffer->Vertices.push_back(video::S3DVertex(1,1,0,  1, 1,-1, clr, 1, 0));
    buffer->Vertices.push_back(video::S3DVertex(0,1,0, -1, 1,-1, clr, 0, 0));
    buffer->Vertices.push_back(video::S3DVertex(1,0,1,  1,-1, 1, clr, 0, 1));
    buffer->Vertices.push_back(video::S3DVertex(1,1,1,  1, 1, 1, clr, 0, 0));
    buffer->Vertices.push_back(video::S3DVertex(0,1,1, -1, 1, 1, clr, 1, 0));
    buffer->Vertices.push_back(video::S3DVertex(0,0,1, -1,-1, 1, clr, 1, 1));
    buffer->Vertices.push_back(video::S3DVertex(0,1,1, -1, 1, 1, clr, 0, 1));
    buffer->Vertices.push_back(video::S3DVertex(0,1,0, -1, 1,-1, clr, 1, 1));
    buffer->Vertices.push_back(video::S3DVertex(1,0,1,  1,-1, 1, clr, 1, 0));
    buffer->Vertices.push_back(video::S3DVertex(1,0,0,  1,-1,-1, clr, 0, 0));
 
    // Recalculate bounding box
    buffer->BoundingBox.reset(0,0,0);
 
    for (u32 i=0; i<12; ++i)
    {
        buffer->Vertices[i].Pos -= core::vector3df(0.5f, 0.5f, 0.5f);
        buffer->Vertices[i].Pos *= size;
        buffer->BoundingBox.addInternalPoint(buffer->Vertices[i].Pos);
    }
 
    SMesh* mesh = new SMesh;
    mesh->addMeshBuffer(buffer);
    buffer->drop();
 
    mesh->recalculateBoundingBox();
    return mesh;
}
 
Take a close look to indices definition, and then to vertices - indices order during render goes as { 0, 1, 2, 3, 4, 5, 6, 7 }, and not as { 0, 2, 1, 0, 3, 2, 1, 5 }.
I'm binding vao, vbo and ibo right before the rendering, so I don't understand what's going on.
Jack_the_Forceman
Posts: 10
Joined: Thu Jan 26, 2012 1:02 am

Re: Issue with native render using OpenGL 4.+/ GLSL 4+

Post by Jack_the_Forceman »

Update: I've noticed that I misplaced some data in a call to CGOpenGL4MaterialRederer::createRenderSourceData()
I was actually passing address of vertices instead of indices... unfortunately fixing this didn't solve my issue, much to my disappointment.
Also, I've added a manual binding of GL_ELEMENT_ARRAY_BUFFER for corresponding index buffer just before, just to make sure:

Code: Select all

 
            GLuint _vao = reinterpret_cast< GLuint >( _nextData->m_pVertexHandleObject );
            GLuint _ib = reinterpret_cast< GLuint >( _nextData->m_pIndexBuffer );
 
            // Bind VAO and index buffer.
            glBindVertexArray( _vao );
            glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, _ib );
 
            // Issue draw command.
            glDrawArrays( _mode, 0, _nextData->m_iIndexCount );
 
Sadly, still no effect.
hendu
Posts: 2600
Joined: Sat Dec 18, 2010 12:53 pm

Re: Issue with native render using OpenGL 4.+/ GLSL 4+

Post by hendu »

I don't know GL4, but in GL2 glDrawArrays didn't use indices, it worked using vertex order, and the correct call was glDrawElements if you had indices.
Jack_the_Forceman
Posts: 10
Joined: Thu Jan 26, 2012 1:02 am

Re: Issue with native render using OpenGL 4.+/ GLSL 4+

Post by Jack_the_Forceman »

hendu wrote:I don't know GL4, but in GL2 glDrawArrays didn't use indices, it worked using vertex order, and the correct call was glDrawElements if you had indices.
Thanks, hendu, looks like that took care of the messed up indices. I don't remember where I've read this, but I was assuming that with bound VAO glDrawArrays in GL4 draws using data from the bound buffer.
Looks like it doesn't work that way.

Nevertheless, after changing the call to glDrawElemets() I now have geometry properly fed. However, there are still some problems:

Image

1) Depth test is still not working. Enabling it right before ender with code

Code: Select all

 
        glEnable( GL_DEPTH_TEST );
        glDepthFunc( GL_LESS );
        glDepthMask( GL_TRUE );
 
produces pitch black screen. Besides, other modes besides GL_ALWAYS also produce black screen - even GL_GREATER.

I guess I need to dig further into the code of COpenGLDriver. I still didn't add some code like glBlendFunc(), but I suspect that isn't the issue. Or is it?
Jack_the_Forceman
Posts: 10
Joined: Thu Jan 26, 2012 1:02 am

Re: Issue with native render using OpenGL 4.+/ GLSL 4+

Post by Jack_the_Forceman »

Update: I've checked the default irrlicht's "Hello World" example, while changing the loaded mesh to dwarf.
Looks like messed up texture on it's axe is just misplaced texcoords:
Image

So that takes care of the incorrect texture.
Now I only need help with depth configuration.
Jack_the_Forceman
Posts: 10
Joined: Thu Jan 26, 2012 1:02 am

Re: Issue with native render using OpenGL 4.+/ GLSL 4+

Post by Jack_the_Forceman »

Update 2: Looks like I also have some troubles with output fragments' color in my shader.
In FS:

Code: Select all

 
    fragColor = vec4( texture( sTexture0, tCoord ).xyz, 0.01 ); // alpha is very close to zero, not equal to it
 
Peoduces just the same result as:

Code: Select all

 
    fragColor = vec4( texture( sTexture0, tCoord ).xyz, 1.0 ); // alpha is 255
 
However, when I use

Code: Select all

 
    fragColor = vec4( texture( sTexture0, tCoord ).xyz, 0 ); // alpha is zero
 
I obviously get a black screen.

On the other hand, result what I'm getting actually draws mesh semi-transparent.
I double checked: texture doesn't use alpha values with less that 255 (I saved it with paint in order to ensure that).

The result looks like this:
Image
Image

My guess is that it's a problem of color initialization.
I saw a code in COpenGLES2Driver from android/ios branch, where before data copying to GPU it's colors are converted by memcpy() into irr::core::array<u8>.
But even if that would solve the issue, I still don't use the color provided by vertex attributes - I simply use texture() fetching based on texcoords.

Does somebody know, if it's related to alpha testing, or something? I did't see a situation like this before, so I don't understand why this occurs.

EDIT: It does NOT happen with the default cube, so I'm completely confused now about this:
Image
Jack_the_Forceman
Posts: 10
Joined: Thu Jan 26, 2012 1:02 am

Re: Issue with native render using OpenGL 4.+/ GLSL 4+

Post by Jack_the_Forceman »

Update 3...

Depth issues are completely dependent on the order of geometry drawn - when rendering 2 or more objects, the one that is rendered first will always be obstructed by the one being rendered afterwards.
Examples:

1st - cube, 2nd - dwarf:
Image

1st - dwarf, 2nd - cube:
Image

That also explains, why parts of dwarf mesh are visible in places they shouldn't be - they are just renderer after the geometry that is nearer to camera.

I'm sorry to bother everyone, but I just can't solve this, concidering I've been fighting this for 4 days straight already.
I don't say that this thing is a bug in irrlicht, but it's definnitely engine-related - I'm almost sure that I'm simply forgetting to swich or configure something - something that either CAnimatedMeshSceneNode, SMaterial or COpenGLDriver does, while I don't... And I haven't found any clues within the engine's code.

Code before rendering not looks like this:

Code: Select all

 
        glEnable( GL_BLEND );
        glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
        glBlendEquation( GL_FUNC_ADD );
        glEnable( GL_DEPTH_TEST );
        gelDepthFunc( GL_LEQUAL );
        glDepthDepthMask( GL_TRUE );
 
        glPolygonOffset( -1.0f, 0.0f );
        glEnable( GL_LINE_SMOOTH );
        glLineWidth( 1.0f );
        glEnable( GL_MULTISAMPLE );
        glEnable( GL_SAMPLE_ALPHA_TO_COVERAGE );
 
I've tried to play around with depth testing - GL_LESS produces completely black screen. Also, blending function is set to ( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ), but regardless of it's enabled or disabled state, the result is the same.

I'm really hoping that anyone of you can help me with this.
Jack_the_Forceman
Posts: 10
Joined: Thu Jan 26, 2012 1:02 am

Re: Issue with native render using OpenGL 4.+/ GLSL 4+

Post by Jack_the_Forceman »

Nailed it.

So basically, Irrlicht has interesting way of definining view and projection matrices (through irr::core::matrix4 class), and for them to be used, zNear and zFar values can be 0 and 1 respectively, and turns out it's actually normal in this case.
Now in most wrappers that come with OpenGL, just like GLFW, a way of projection matrix definition is slightly different, and it's perfectly conforms a simple rule for current OpenGL pipeline: neither zNear not zFar value can NOT be equal to zero.

That's why getting everything to work while using most of irrlicht's functionality is a bit tricky: a hint to use values like 0.1 for zNear is not working in this case.
However, zNear actually HAS to be in [ 0.0, 1.0 ] range in this case. For me, a value of 0.5 worked out like a charm. Also, it should be noted, that zFar in this case must be at 1000.0+ in order to have some reasonable amount of data actually rendered on screen.

Finally, even when all of this is done, it's still not the end: by default, Irrlicht uses GL_LEQUAL depth testing function, but in my case it causes some ZFighting for complicated and concave meshes in case they are completely opaque.
Irrlicht renders all the geometry in 2 passes - 1st is everything that's solid, rendered with GL_LESS function, and 2nd is all transparent objects, rendered with GL_LEQUAL.
But I use generic multi-pass rendering, with manual definition of render pass configurations for each object, per each of it's states. My mistake was to use GL_LEQUAL in all occasions. Turning it to GL_LESS on the first pass has actually solved everything.

Result:
Image

Thanks everyone, for hints that actually helped me to find all these solutions!
mongoose7
Posts: 1227
Joined: Wed Apr 06, 2011 12:13 pm

Re: Issue with native render using OpenGL 4.+/ GLSL 4+

Post by mongoose7 »

What! This is *not* a solution.

Firstly, near and far values are set by the user, not Irrlicht. I don't know where you are reading them, but just two points: 1) the near value is mapped by the projection matrix to 0 and the far value to 1; and Irrlicht's matrices are the transpose of the real thing. Are you getting the values after the projection matrix? If so, you cannot then adduce the rules of OpenGL, which apply before the transformations.

Secondly, depth testing is turned off for transparent objects, so the GL_LEQUAL is a red herring.

Look, I think you are doing a botched job if you have these misunderstandings and if you go for easy fixes with very thin motivation.
Jack_the_Forceman
Posts: 10
Joined: Thu Jan 26, 2012 1:02 am

Re: Issue with native render using OpenGL 4.+/ GLSL 4+

Post by Jack_the_Forceman »

mongoose7 wrote:Look, I think you are doing a botched job if you have these misunderstandings and if you go for easy fixes with very thin motivation.
Well, I can't say you're wrong about the lack of understanding. I'm relatively new to raw OpenGL and I'm trying to learn it step by step, while doing another task.
Motivation is not a matter here - I'm actually pretty well motivated to write my code most properly and cleanly. I just need help with some pitfalls that I (rarely) find to be a problem I can't overcome by debugging and code-digging.
I prefer to not use already-written code, especially from "fast" tutorials - but outside of that, only actual engines can be a really good code reference for practical solutions.
And then I ran into this problem. I'm actually glad I've posted it here, because the discussion process gave me several ideas on how to solve it.

I think I should clarify myself here.
I don't use Irrlicht's rendering functionality at all. I've actually written my own SceneManager, GUIManager and so on. They all needed to be created anew in order to meet the points I' chasing while writing this engine.
I only use IVideoDriver in order to load textures, as I'm too lazy to write GAPI-independent texture loaders that are already implemented and well tested.
I also use ISceneManager for the sake of obtaining pointers to things like IGeometryCreator, and for employing MeshLoaders, but aside from that - I'm using my own scene arrangement, written from scratch.

Now, on to the next points.
mongoose7 wrote:Firstly, near and far values are set by the user, not Irrlicht
Well, I didn't say I *hardcoded* them, or took them from Irrlicht' code - these are fully configurable from the user's POV. I was only saying that standard values that are recommended in most cases didn't work - but about that, read below.
mongoose7 wrote:Are you getting the values after the projection matrix?
I calculate projection matrix myself. And I *apply" it myself, within the render() method for my CGCameraSceneObejct. Just like View matrix. Just like world transformation matrix for every single SceneObject on the scene. Without any call to COpenGLDriver, but using my custom MaterialRenderer interface, that sort of replaces IVideoDriver here in a sense. OpenGL3+ CP expects w/v/p matrices to be only passed down to shader program as mat4 uniform - things like IVideoDriver::setTransform() are simply not needed here.
However, about transposing - as I'm calculating matrices in correspondance to OpenGL's matrix format (calculation is a part of renderer's interface, so it can be customized per-implementation), I don't think that to actually be an issue here.

Finally, I found 1 more thing - the reason I've been picking values like 0.5 was actually because of OpenGL driver for my laptop GPU (radeon 6700M) - on NV 670 I could get away with the value of 0.1 (recommended in most cases) though.
The rest, as I understand, was implemented properly - but I didn't understand what you've ment about mapping to [ 0.0, 1.0 ] range.
mongoose7 wrote:1) the near value is mapped by the projection matrix to 0 and the far value to 1;
I will debug this immeadiately, as I apparently still don't quite understand this, in therms of Irrlicht.

And one last thing - if anyone goes here to ask some "not so easy" questions, and while there are really few helpful hints, this anyone thoroughly investigates and tries hard to solve it himself, there is no actual need to say that he/she has slim motivation - without motivation, a challenge of such an issue encounterred would not even have happened. That's what I think. Assuming you're not a troll. :)
mongoose7
Posts: 1227
Joined: Wed Apr 06, 2011 12:13 pm

Re: Issue with native render using OpenGL 4.+/ GLSL 4+

Post by mongoose7 »

mongoose7 wrote:Look, I think you are doing a botched job if you have these misunderstandings and if you go for easy fixes with very thin motivation.
This doesn't mean *you* lack motivation. It means you appear to be easily motivated to make quick fixes without any deeper understanding. That's it.
Post Reply