void MultiDrawIndirect::SetupMultiDrawParameters()
{
    unsigned int                        j;
    NvModel*                            pData;
    unsigned int                        VertexOffset;
    unsigned int                        IndexOffset;

    glBindBuffer(GL_DRAW_INDIRECT_BUFFER, m_IndirectDrawBuffer);
    CHECK_GL_ERROR();

    VertexOffset = 0;
    IndexOffset = 0;

    CHECK_GL_ERROR();

    pData = m_Model->getModel();

    for (j = 0; j < m_GridSize * m_GridSize; j++)
    {
        VertexOffset = (j % MAX_MODEL_INSTANCES) * pData->getCompiledVertexCount();

        m_MultidrawCommands[j].count = pData->getCompiledIndexCount(NvModelPrimType::TRIANGLES);
        m_MultidrawCommands[j].instanceCount = 1;
        m_MultidrawCommands[j].firstIndex = IndexOffset;
        m_MultidrawCommands[j].baseVertex = VertexOffset;
        m_MultidrawCommands[j].baseInstance = j;
    }

    IndexOffset += pData->getCompiledIndexCount();

    glBindBuffer(GL_DRAW_INDIRECT_BUFFER, 0);
    CHECK_GL_ERROR();
}
void MultiDrawIndirect::DrawAsSingleCalls()
{
    unsigned int                        j;
    NvModel*                            pData;
    unsigned int                        VertexOffset;
    unsigned int                        IndexOffset;

    VertexOffset = 0;
    IndexOffset = 0;

    glBindVertexArray(m_VertexArrayObject);

    pData = m_Model->getModel();

    for (j = 0; j < m_GridSize * m_GridSize; j++)
    {
        VertexOffset = (j % MAX_MODEL_INSTANCES) * pData->getCompiledVertexCount();

        glUniform2f(m_SceneShader->m_PositionUHandle, m_Offsets[2 * j], m_Offsets[(2 * j) + 1]);

        glDrawElementsBaseVertex(  GL_TRIANGLES,
                                    pData->getCompiledIndexCount(NvModelPrimType::TRIANGLES),
                                    GL_UNSIGNED_INT,
                                    (GLvoid *) (IndexOffset * sizeof(IndexOffset)),
                                    VertexOffset);
    }

    IndexOffset += pData->getCompiledIndexCount();

    glBindVertexArray(0);
    CHECK_GL_ERROR();
}
void MultiDrawIndirect::SetConstants()
{
    std::vector<NvGLModel*>::iterator   ii;
    NvModel*                            pData;
    int32_t                             SizeOfCompiledVertex;
    unsigned int                        NumberOfCompiledVertices;
    unsigned int                        NumberOfIndices;

    pData = m_Model->getModel();

    NumberOfCompiledVertices = 0;
    NumberOfIndices = 0;

    SizeOfCompiledVertex = pData->getCompiledVertexSize();

    NumberOfCompiledVertices += pData->getCompiledVertexCount();
    NumberOfIndices += pData->getCompiledIndexCount(NvModelPrimType::TRIANGLES);

    m_IndexSize = sizeof(uint32_t);
    m_VertexSize = sizeof(float) * SizeOfCompiledVertex;

    m_SizeofIndexBuffer = NumberOfIndices * m_IndexSize;

    // Vertices
    m_SizeofVertexBuffer = NumberOfCompiledVertices * m_VertexSize * m_MaxModelInstances;

    m_OffsetofInstanceBuffer = m_SizeofVertexBuffer;

    m_SizeofVertexBuffer += 2 * sizeof(GLfloat) * m_MaxGridSize * m_MaxGridSize;
}
示例#4
0
void InstancingApp::initGLObjects( int32_t sceneIndex, float* pV, int32_t* pI, NvModelGL* pMdl )
{
    NvModelPrimType::Enum prim;
    NvModel *pBaseMdl = pMdl->getModel();
    int32_t        floatCount     = pBaseMdl->getCompiledVertexCount() * pBaseMdl->getCompiledVertexSize() * MAX_INSTANCES;
    int32_t        intCount = pBaseMdl->getCompiledIndexCount(prim) * MAX_INSTANCES;

    // create vbo from the data
    glGenBuffers(1, &m_vboID[sceneIndex]);
    glBindBuffer(GL_ARRAY_BUFFER, m_vboID[sceneIndex]);
    glBufferData(GL_ARRAY_BUFFER, floatCount * sizeof(float) + 6 * MAX_OBJECTS * sizeof(float), pV, GL_STATIC_DRAW);
    glBindBuffer(GL_ARRAY_BUFFER, 0);

    // create ibo from the data
    glGenBuffers(1, &m_iboID[sceneIndex]);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_iboID[sceneIndex]);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, intCount * sizeof(uint32_t), pI, GL_STATIC_DRAW);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
}
示例#5
0
bool InstancingApp::initSceneInstancingData( int32_t sceneIndex )
{
    NvModelPrimType::Enum prim;
    NvModelGL* pMdl = m_pModel[sceneIndex];
    NvModel *pBaseMdl = pMdl->getModel();
    int32_t        floatCount     = pBaseMdl->getCompiledVertexCount() * pBaseMdl->getCompiledVertexSize() * MAX_INSTANCES;
    int32_t        intCount       = pBaseMdl->getCompiledIndexCount(prim) * MAX_INSTANCES;

    // array big enough to hold n instances and data for hw instancing
    // after n copies of the vertex data of the object there is room
    // for all position and rotation data for all instances
    float* pV            = new float[ floatCount + 6 * MAX_OBJECTS ];
    GLint* pI            = new GLint[ intCount ];

    // early out if no data
    if( pV == 0 || pI == 0 )
    {
        if( pV )
            delete[] pV;
        if( pI )
            delete[] pI;

        return false;
    }

    // ptr to the per object instancing data in the vbo
    float* phwInstanceData = pV + floatCount;

    // init data for this scene
    initSceneColorPalette( sceneIndex );
    initPerInstanceRotations( sceneIndex, phwInstanceData );
    initPerInstancePositions( sceneIndex, phwInstanceData );
    initModelCopies( sceneIndex, pV, pI, pMdl );
    initGLObjects( sceneIndex, pV, pI, pMdl );

    // free temp data
    delete[] pV;
    delete[] pI;

    return true;
}
示例#6
0
void InstancingApp::initModelCopies( int32_t sceneIndex, float* pV, int32_t* pI, NvModelGL* pMdl )
{
    NvModel *pBaseMdl = pMdl->getModel();

    NvModelPrimType::Enum prim;
    int32_t    vtxSize = pBaseMdl->getCompiledVertexSize();
    int32_t    vtxCount = pBaseMdl->getCompiledVertexCount();
    int32_t    idxCount = pBaseMdl->getCompiledIndexCount(prim);
    int32_t    tcOff         = pBaseMdl->getCompiledTexCoordOffset();
    const float* pModel  = pBaseMdl->getCompiledVertices();

    // write MAX_INSTANCES copies of the scene object to be instanced to
    // a big vertex buffer and index buffer - this data is used in the
    // shader instancing rendering path
    for( int32_t i = 0; i < MAX_INSTANCES; ++i )
    {
        int32_t voff = vtxCount * vtxSize * i;
        int32_t ioff = idxCount * i;

        for( int32_t v = 0; v < vtxCount; ++v )
        {
            // copy original vertex
            memcpy( (void*) &pV[ voff + v * vtxSize ],
                    (void*) &pModel[ v * vtxSize ],
                    vtxSize * sizeof( float) );

            // patch instance id into .z component of the 3d texture coordinates
            pV[ voff + v * vtxSize +  tcOff  + 2 ] = float( i );
        }

        // copy indices and modify them accordingly
        for( int32_t idx = 0; idx < idxCount; ++idx )
        {
            pI[ioff + idx] = *(pBaseMdl->getCompiledIndices(prim) + idx);
            pI[ ioff + idx ] += vtxCount * i;
        }
    }
}
void MultiDrawIndirect::SetupMultiDrawIndirectData( GLint                       PositionHandle,
                                                    GLint                       NormalHandle,
                                                    GLint                       TexcoordHandle,
                                                    GLint                       InstanceHandle)
{
    GLuint                              BufferID;
    NvModel*                            pData;
    int32_t                             PositionSize;
    int32_t                             NormalSize;
    int32_t                             TexCoordSize;

    pData = m_Model->getModel();

    PositionSize = pData->getPositionSize();
    NormalSize = pData->getNormalSize();
    TexCoordSize = pData->getTexCoordSize();

    SetConstants();

    glBindVertexArray(m_VertexArrayObject);

    glGenBuffers(1, &BufferID);
    glBindBuffer(GL_ARRAY_BUFFER, BufferID);

    glBufferData(   GL_ARRAY_BUFFER,
                    m_SizeofVertexBuffer,
                    NULL,
                    GL_STATIC_DRAW);
    glGenBuffers(1, &BufferID);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, BufferID);

    glBufferData(   GL_ELEMENT_ARRAY_BUFFER,
                    m_SizeofIndexBuffer,
                    NULL,
                    GL_STATIC_DRAW);

    SetupMultipleModelData();

    glVertexAttribPointer(  PositionHandle,
                            PositionSize,
                            GL_FLOAT,
                            GL_FALSE,
                            m_VertexSize,
                            0);
    glEnableVertexAttribArray(PositionHandle);

    glVertexAttribPointer(  NormalHandle,
                            NormalSize,
                            GL_FLOAT,
                            GL_FALSE,
                            m_VertexSize,
                            OFFSET(pData->getCompiledNormalOffset() * sizeof(float)));
    glEnableVertexAttribArray(NormalHandle);

    glVertexAttribPointer(  TexcoordHandle,
                            TexCoordSize,
                            GL_FLOAT,
                            GL_FALSE,
                            m_VertexSize,
                            OFFSET(pData->getCompiledTexCoordOffset() * sizeof(float)));
    glEnableVertexAttribArray(TexcoordHandle);
    
    if (InstanceHandle >= 0) {
        glVertexAttribPointer(  InstanceHandle,
                                2,
                                GL_FLOAT,
                                GL_FALSE,
                                0,
                               OFFSET(m_OffsetofInstanceBuffer));
        glEnableVertexAttribArray(InstanceHandle);
        glVertexAttribDivisor(InstanceHandle,1);
    }

    glBindVertexArray(0);
    CHECK_GL_ERROR();
}
void MultiDrawIndirect::SetupMultipleModelData()
{
    NvModel*                            pData;
    float*                              pVertexData;
    uint32_t*                           pIndexData;
    unsigned int                        j;

    pIndexData = (uint32_t *) glMapBufferRange( GL_ELEMENT_ARRAY_BUFFER, 0,
                                                m_SizeofIndexBuffer,
                                                GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT);

    pVertexData = (float *) glMapBufferRange(   GL_ARRAY_BUFFER, 0,
                                                m_SizeofVertexBuffer,
                                                GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT);

    
    pData = m_Model->getModel();

    for (unsigned int k = 0; k < m_MaxModelInstances; k++)
    {
        float *pPositionData, Scale;

        memcpy( pVertexData,
                pData->getCompiledVertices(),
                pData->getCompiledVertexCount() * m_VertexSize);

        pPositionData = pVertexData;

        Scale = 1.0f + (rand() / (float) RAND_MAX) * 3.0f;;

        for (int z = 0; z < pData->getCompiledVertexCount(); z++)
        {
            pPositionData[0] = pPositionData[0];
            pPositionData[1] = pPositionData[1] * Scale;
            pPositionData[2] = pPositionData[2];

            pPositionData += pData->getCompiledVertexSize();
        }

        pVertexData += pData->getCompiledVertexCount() * pData->getCompiledVertexSize();
    }

    memcpy( pIndexData,
            pData->getCompiledIndices(NvModelPrimType::TRIANGLES),
            pData->getCompiledIndexCount() * m_IndexSize);

    pIndexData += pData->getCompiledIndexCount();

    float* pInstData = (float*)pVertexData;

    for (j = 0; j < m_MaxGridSize; j++)
    {
        GetGridPoints(j, m_Offsets);
    }

    for (j = 0; j < m_MaxGridSize * m_MaxGridSize; j++)
    {
        *(pInstData++) = m_Offsets[2 * j];
        *(pInstData++) = m_Offsets[(2 * j) + 1];
    }

    glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
    glUnmapBuffer(GL_ARRAY_BUFFER);
}
bool InstancedTessellation::initPerModelTessellationInstancingData( NvGLModel* mdl, int32_t modelIndex )
{
    NvModel*       pModel         = mdl->getModel();
    int              numFaces       = pModel->getCompiledIndexCount( NvModelPrimType::TRIANGLES ) / 3;
    const GLuint*    pIndices       = pModel->getCompiledIndices( NvModelPrimType::TRIANGLES );
    const float*     pVertices      = pModel->getCompiledVertices();
    int                 floatsPerV     = pModel->getCompiledVertexSize();
    int                 vtxOffset      = pModel->getCompiledPositionOffset();
    int                 normalOffset   = pModel->getCompiledNormalOffset();
    int                 textureOffset  = pModel->getCompiledTexCoordOffset();
    PerInstanceData* pId            = new PerInstanceData[ numFaces ];

    m_pTriangleData[ modelIndex ] = pId;

    // build per instance/triangle data in memory
    for( int i = 0; i < numFaces; ++i )
    {
        GLuint          idx[ 3 ];
        const float* pVertex[ 3 ];
        nv::vec3f    v[ 3 ];
        nv::vec3f    n[ 3 ];
        nv::vec2f    txt[ 3 ];

        // get indices
        idx[0] = pIndices[ i * 3 + 0 ];
        idx[1] = pIndices[ i * 3 + 1 ];
        idx[2] = pIndices[ i * 3 + 2 ];

        // get vertices and normals
        pVertex[0] = pVertices + floatsPerV * idx[ 0 ];
        pVertex[1] = pVertices + floatsPerV * idx[ 1 ];
        pVertex[2] = pVertices + floatsPerV * idx[ 2 ];

        // copy vertex data
        v[0] = *((nv::vec3f*)(pVertex[0]+vtxOffset));
        v[1] = *((nv::vec3f*)(pVertex[1]+vtxOffset));
        v[2] = *((nv::vec3f*)(pVertex[2]+vtxOffset));
        n[0] = nv::normalize( *((nv::vec3f*)(pVertex[0]+normalOffset)) );
        n[1] = nv::normalize( *((nv::vec3f*)(pVertex[1]+normalOffset)) );
        n[2] = nv::normalize( *((nv::vec3f*)(pVertex[2]+normalOffset)) );
        txt[0] = *( (nv::vec2f*) (pVertex[0]+textureOffset) );
        txt[1] = *( (nv::vec2f*) (pVertex[1]+textureOffset) );
        txt[2] = *( (nv::vec2f*) (pVertex[2]+textureOffset) );

        // initialize interpolated vertices
        pId[ i ].m_p0         = v[0];
        pId[ i ].m_p1         = v[1];
        pId[ i ].m_p2         = v[2];
        pId[ i ].m_n0         = n[0];
        pId[ i ].m_n1         = n[1];
        pId[ i ].m_n2         = n[2];
        //pId[ i ].m_t0t1       = nv::vec4f(txt[0].x, txt[0].y, txt[1].x, txt[1].y );
        //pId[ i ].m_t2         = nv::vec2f(txt[2].x, txt[2].y );
    }

    glGenBuffers(1, &m_perTriangleDataVboID[modelIndex]);
    glBindBuffer(GL_ARRAY_BUFFER, m_perTriangleDataVboID[modelIndex]);
    glBufferData(GL_ARRAY_BUFFER, numFaces * sizeof(PerInstanceData), pId, GL_STATIC_DRAW);
    glBindBuffer(GL_ARRAY_BUFFER, 0);

    return true;
}
void InstancedTessellation::drawModelLitInstancingOFF()
{
    BaseShader* shader = m_tessMode == eNPatch ? m_npatchShader : m_deformationShader;

    if( m_tessMode == eNPatch )
        m_npatchShader->enable();
    else
        m_deformationShader->enable();

    if( m_tessMode == eDeformation )
    {
        float time = m_time;

        glUniform1f( m_deformationShader->m_timeHandle, time );
    }

    //send matrices
    glUniformMatrix4fv(shader->m_modelViewMatrixHandle, 1, GL_FALSE,  m_viewMatrix._array);
    glUniformMatrix4fv(shader->m_projectionMatrixHandle, 1, GL_FALSE, m_projectionMatrixHandle._array);

    glUniform4fv(shader->m_lightPositionHandle1, 1, m_lightPositionEye._array);

    glUniform4f(shader->m_colorHandle, m_modelColor.x, m_modelColor.y, m_modelColor.z, 1.0f);

    //m_normalMatrixHandle now contains a 3x3 inverse component of the m_modelViewMatrixHandle
    //hence, we need to transpose this before sending it to the shader
    glUniformMatrix4fv(shader->m_normalMatrixHandle, 1, GL_FALSE, m_normalMatrixHandle._array);

    glBindBuffer(GL_ARRAY_BUFFER, m_tessVboID[m_tessFactor-1] );
    if( m_wireframe == false )
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_tessIboID[m_tessFactor-1] );
    else
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_wireframeTessIboID[m_tessFactor-1] );

    glVertexAttribPointer(shader->m_b01Handle, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), 0 ) ;
    glEnableVertexAttribArray(shader->m_b01Handle);

    NvModel*       pModel         = m_pModel[m_modelIndex]->getModel();
    int              numFaces       = pModel->getCompiledIndexCount( NvModelPrimType::TRIANGLES ) / 3;

    for( int i = 0; i < numFaces; ++i )
    {
        if( m_tessMode == eNPatch )
        {
            glUniform3fv( m_npatchShader->m_posHandle, 3, (GLfloat*)&((m_pTriangleData[m_modelIndex])[i].m_p0) );
            glUniform3fv( m_npatchShader->m_normHandle, 3, (GLfloat*)&((m_pTriangleData[m_modelIndex])[i].m_n0) );
        }
        else
        {
            glUniform3fv( m_deformationShader->m_posHandle, 3, (GLfloat*)&((m_pTriangleData[m_modelIndex])[i].m_p0) );
            glUniform3fv( m_deformationShader->m_normHandle, 3, (GLfloat*)&((m_pTriangleData[m_modelIndex])[i].m_n0) );
        }

        if( m_wireframe == false )
            glDrawElements(GL_TRIANGLES, ( m_tessFactor * m_tessFactor ) * 3, GL_UNSIGNED_INT, 0);
        else
            glDrawElements(GL_LINES, ( ( ( m_tessFactor + 1 ) * m_tessFactor ) / 2 ) * 3 * 2, GL_UNSIGNED_INT, 0);
    }

    glBindBuffer(GL_ARRAY_BUFFER, m_tessVboID[m_tessFactor-1] );
    glDisableVertexAttribArray(shader->m_b01Handle);

    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
}
void InstancedTessellation::drawModelLitInstancingON()
{
    InstancedTessShader* shader = m_tessMode == eNPatch ? m_instancedNPatchShader : m_instancedDeformationShader;

   shader->enable();

    if( m_tessMode == eDeformation )
    {
        float time = m_time;

        m_deformationShader->setUniform1f( m_deformationShader->m_timeHandle, time );
    }

    shader->setUniformMatrix4fv(shader->m_modelViewMatrixHandle,  m_viewMatrix._array, 1, GL_FALSE);
    shader->setUniformMatrix4fv(shader->m_projectionMatrixHandle, m_projectionMatrixHandle._array, 1, GL_FALSE);
    shader->setUniform4f(shader->m_lightPositionHandle1, m_lightPositionEye.x, m_lightPositionEye.y, m_lightPositionEye.z, m_lightPositionEye.w);
    shader->setUniform4f(shader->m_colorHandle, m_modelColor.x, m_modelColor.y, m_modelColor.z, 1.0f);

    //m_normalMatrixHandle now contains a 3x3 inverse component of the m_modelViewMatrixHandle
    //hence, we need to transpose this before sending it to the shader
    shader->setUniformMatrix4fv(shader->m_normalMatrixHandle, m_normalMatrixHandle._array, 1, GL_FALSE);

    glBindBuffer(GL_ARRAY_BUFFER, m_tessVboID[m_tessFactor-1] );
    if( m_wireframe == false )
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_tessIboID[m_tessFactor-1] );
    else
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_wireframeTessIboID[m_tessFactor-1] );

    glVertexAttribPointer(shader->m_b01Handle, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), 0 ) ;
    glEnableVertexAttribArray(shader->m_b01Handle);

    NvModel*       pModel         = m_pModel[m_modelIndex]->getModel();
    int            numFaces     = pModel->getCompiledIndexCount( NvModelPrimType::TRIANGLES ) / 3;

    glBindBuffer(GL_ARRAY_BUFFER, m_perTriangleDataVboID[m_modelIndex] );

    glVertexAttribPointer(shader->m_posHandle0, 3, GL_FLOAT, GL_FALSE, 18 * sizeof(float), 0 ) ;
    glEnableVertexAttribArray(shader->m_posHandle0);
    glVertexAttribPointer(shader->m_posHandle1, 3, GL_FLOAT, GL_FALSE, 18 * sizeof(float), (GLvoid*)(3 * sizeof(float) ) ) ;
    glEnableVertexAttribArray(shader->m_posHandle1);
    glVertexAttribPointer(shader->m_posHandle2, 3, GL_FLOAT, GL_FALSE, 18 * sizeof(float), (GLvoid*)(6 * sizeof(float) ) ) ;
    glEnableVertexAttribArray(shader->m_posHandle2);
    glVertexAttribPointer(shader->m_normHandle0, 3, GL_FLOAT, GL_FALSE, 18 * sizeof(float), (GLvoid*)(9 * sizeof(float) ) ) ;
    glEnableVertexAttribArray(shader->m_normHandle0);
    glVertexAttribPointer(shader->m_normHandle1, 3, GL_FLOAT, GL_FALSE, 18 * sizeof(float), (GLvoid*)(12 * sizeof(float) ) ) ;
    glEnableVertexAttribArray(shader->m_normHandle1);
    glVertexAttribPointer(shader->m_normHandle2, 3, GL_FLOAT, GL_FALSE, 18 * sizeof(float), (GLvoid*)(15 * sizeof(float) ) ) ;
    glEnableVertexAttribArray(shader->m_normHandle2);

    glVertexAttribDivisorInternal( shader->m_posHandle0, 1 );
    glVertexAttribDivisorInternal( shader->m_posHandle1, 1 );
    glVertexAttribDivisorInternal( shader->m_posHandle2, 1 );
    glVertexAttribDivisorInternal( shader->m_normHandle0, 1 );
    glVertexAttribDivisorInternal( shader->m_normHandle1, 1 );
    glVertexAttribDivisorInternal( shader->m_normHandle2, 1 );

    if( m_wireframe == false )
        glDrawElementsInstancedInternal(GL_TRIANGLES, ( m_tessFactor * m_tessFactor ) * 3, GL_UNSIGNED_INT, 0, numFaces );
    else
        glDrawElementsInstancedInternal(GL_LINES, ( ( ( m_tessFactor + 1 ) * m_tessFactor ) / 2 ) * 3 * 2, GL_UNSIGNED_INT, 0, numFaces );

    glVertexAttribDivisorInternal( shader->m_posHandle0, 0 );
    glVertexAttribDivisorInternal( shader->m_posHandle1, 0 );
    glVertexAttribDivisorInternal( shader->m_posHandle2, 0 );
    glVertexAttribDivisorInternal( shader->m_normHandle0, 0 );
    glVertexAttribDivisorInternal( shader->m_normHandle1, 0 );
    glVertexAttribDivisorInternal( shader->m_normHandle2, 0 );

    glDisableVertexAttribArray(shader->m_posHandle0);
    glDisableVertexAttribArray(shader->m_posHandle1);
    glDisableVertexAttribArray(shader->m_posHandle2);
    glDisableVertexAttribArray(shader->m_normHandle0);
    glDisableVertexAttribArray(shader->m_normHandle1);
    glDisableVertexAttribArray(shader->m_normHandle2);

    glBindBuffer(GL_ARRAY_BUFFER, m_tessVboID[m_tessFactor-1] );
    glDisableVertexAttribArray(shader->m_b01Handle);

    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
}