Hi Robert,

Oops -- I sent this earlier today but apparently to the bounces list; that 
explains the confusion on GitHub -- my mistake.  This was supposedly sent right 
before I posted the PR.  Here's the original text:


I think I found a bug in 3.6.1.  I am loading a FLT model and it's causing a 
crash in my application to draw it.  The same model does not crash in OSG 3.4.  
I think I've finally tracked down the cause and have a candidate solution too.

A few weeks back I saw a similar crash in my own code, and figured it was due 
to incorrect usage of the binding flags on osg::Array.  Much of our code was 
using osg::Geometry::setNormalBinding() (and related methods).  During 
debugging, I was able to determine my normals were crashing in 3.6, and the 
problem went away when I used the osg::Array(osg::Array::Binding) signature -- 
i.e. assigning a binding on construction.  At the time I thought it was 
something I was doing wrong and moved on.

The problem showed up again earlier this week but not in my code, and not 
manifesting in exactly the same way.  Here's the run-down of what's going on:

- Loading FLT model
- FLT model loads a face, which has vertices, textures, and normals
- FLT uses getOrCreateNormalArray(), which allocates an array (BIND_UNDEFINED) 
and sets it on the geometry
- Geometry::addVertexBufferObjectIfRequired() is called on the normals, but 
nothing done due to BIND_UNDEFINED
- FLT later sets normals to BIND_PER_VERTEX appropriately, which is a direct 
set and does not do anything to the Geometry's VBOs
- First frame starts to render
- Geometry::drawVAImpl calls vas->setNormalArray()
- VertexArrayState::setArray() calls new_array->getOrCreateGLBufferObject(), 
which returns 0.  This is the first major problem.
- Because vbo is NULL, unbindindVertexBufferObject() is called, leading to 
GL_ARRAY_BUFFER to go to 0
- vad->enable_and_dispatch() gets called and does glVertexAttribPointer() with 
a non-NULL data ptr, which is a GL error because array buffer is 0

Unwinding the error:
- enable_and_dispatch() shouldn't be called if ptr is non-NULL and no 
GL_ARRAY_BUFFER is 0
- GL_ARRAY_BUFFER is set to 0 because there is no VBO set up for the normal 
array
- There is no normal array because the only place it seems to be created is in 
setNormalArray(), which fails because at that time, it is BIND_UNDEFINED
- Binding gets swapped from BIND_UNDEFINED to BIND_PER_VERTEX after 
setNormalArray(), leading to the error

There are several possible solutions I can see.  You can probably see more:
1) Change FLT plugin to assign array binding per vertex on construction of 
array.  Seems poor because invariably this bug is crashing other code -- maybe 
it's the cause of the DXF that Brian Hutchison reported earlier this week?
2) Update Array::setBinding() to create the VBO if needed.  I do not know if 
this is possible nor how to do it.
3) "Lazily" detect this issue somewhere in the rendering calls and create VBO 
there if necessary



PR 554 was an attempt at approach #3 but I agree with your assessment on 
GitHub.  It does not solve the problem in all cases.

Attached is a demo of the problem that generates a console warning.  More 
complex scenes can cause crashes.  The red triangle has the problem, but the 
green one does not.

 - Dan

cmake_minimum_required(VERSION 2.6)

SET(PROJECT_NAME arraybug)

PROJECT(${PROJECT_NAME})

FIND_PACKAGE(OpenThreads)
FIND_PACKAGE(osg)
FIND_PACKAGE(osgDB)
FIND_PACKAGE(osgUtil)
FIND_PACKAGE(osgGA)
FIND_PACKAGE(osgViewer)
FIND_PACKAGE(osgText)

SET(SOURCES
    main.cpp
)

INCLUDE_DIRECTORIES(${OPENTHREADS_INCLUDE_DIR} ${OSG_INCLUDE_DIR})

LINK_DIRECTORIES(${OSG_LIB_DIR})

ADD_EXECUTABLE(${PROJECT_NAME} ${SOURCES})

TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${OSG_LIBRARIES} ${OSGVIEWER_LIBRARIES} 
${OSGUTIL_LIBRARIES} ${OSGDB_LIBRARIES} ${OSGGA_LIBRARIES} ${OSGTEXT_LIBRARIES} 
${OPENTHREADS_LIBRARIES})
#include <osg/Geode>
#include <osg/Geometry>
#include <osgViewer/Viewer>
#include <osgViewer/ViewerEventHandlers>

osg::Node* createTriangle(float x, bool earlyBinding, const osg::Vec4f& color)
{
    osg::Geode* geode = new osg::Geode;
    osg::Geometry* geom = new osg::Geometry;
    geom->setUseVertexArrayObject(true);
    geom->setUseVertexBufferObjects(true);

    osg::Vec3Array* vertices = new osg::Vec3Array();
    vertices->push_back(osg::Vec3(x - 100, 0, -100));
    vertices->push_back(osg::Vec3(x, 0, 100));
    vertices->push_back(osg::Vec3(x, 0, -100));

    osg::Vec3Array* normals = new osg::Vec3Array;
    normals->push_back(osg::Vec3(0, -1, 0));
    normals->push_back(osg::Vec3(0, -1, 0));
    normals->push_back(osg::Vec3(0, -1, 0));
    if (earlyBinding)
        normals->setBinding(osg::Array::BIND_PER_VERTEX);

    osg::Vec4Array* colors = new osg::Vec4Array(osg::Array::BIND_OVERALL);
    colors->push_back(color);

    geom->addPrimitiveSet(new osg::DrawArrays(GL_TRIANGLES, 0, 3));
    geom->setVertexArray(vertices);
    geom->setNormalArray(normals);
    geom->setColorArray(colors);
    geode->addDrawable(geom);

    // Warning gets generated due to this line not causing (eventually) a VBO 
creation
    if (!earlyBinding)
        normals->setBinding(osg::Array::BIND_PER_VERTEX);
    return geode;
}

osg::Node* createScene()
{
    osg::Group* group = new osg::Group;

    // Reddish: Generates warning
    group->addChild(createTriangle(-100, false, osg::Vec4f(1, 0.5, 0.5, 1)));

    // Greenish: No warnings
    group->addChild(createTriangle(100, true, osg::Vec4f(0.5,1,0.5,1)));

    return group;
}

int main(int argc, char** argv)
{
    osg::ArgumentParser arguments(&argc, argv);

    // construct the viewer.
    osgViewer::Viewer viewer(arguments);
    viewer.setSceneData(createScene());
    viewer.setUpViewInWindow(100, 100, 800, 600);
    viewer.addEventHandler(new osgViewer::StatsHandler());

    return viewer.run();
}
_______________________________________________
osg-users mailing list
osg-users@lists.openscenegraph.org
http://lists.openscenegraph.org/listinfo.cgi/osg-users-openscenegraph.org

Reply via email to