From 849d2fdc8f3f8256b84c8fed55fd9555fbc0f5b2 Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Thu, 13 Mar 2008 16:40:45 +0000 Subject: [PATCH] From Gino van den Bergen, "I've added a few fixes to the VRML 2.0 plugin: 1) Full DOS paths are now correctly opened by OpenVRML. A URL containing a DOS path should be "file:///C:data/blah" rather than "file://C:data/blah". 2) The last primitive defined in "coordIndex" is now added if the "coordIndex" is not terminated by -1. 3) Smoothed normals are computed if no normal field is provided. Currently, there is no support for "creaseAngle", so all edges (even the ones sharper than the creaseAngle) are smoothed. I might add this in the future if demand rises. 4) If an IndexedFaceSet contains only triangles or quads then the primitive type is set to TRIANGLES or QUADS, and the primset becomes DrawArrays rather than DrawArrayLengths. Question: I noticed that for DrawArrays you can still provide an index array. Would the rendering be faster if I'd create DrawElements primsets rather than DrawArrays? Phrased differently, what is the benefit of using DrawElements over DrawArrays, as there is clearly not a one-to-one mapping of these concepts to their OpenGL counterparts? 5) Objects are added to the transparent bin and blend mode is enabled only if the transparency is nonzero. Rendered transparent objects no longer write the depth buffer." --- src/osgPlugins/vrml/ReaderWriterVRML2.cpp | 217 +++++++++++++++++----- 1 file changed, 168 insertions(+), 49 deletions(-) diff --git a/src/osgPlugins/vrml/ReaderWriterVRML2.cpp b/src/osgPlugins/vrml/ReaderWriterVRML2.cpp index 1d4292385..02ad6ab7b 100644 --- a/src/osgPlugins/vrml/ReaderWriterVRML2.cpp +++ b/src/osgPlugins/vrml/ReaderWriterVRML2.cpp @@ -38,6 +38,7 @@ #include #include #include +#include #include #include @@ -86,10 +87,11 @@ osgDB::ReaderWriter::ReadResult ReaderWriterVRML2::readNode(const std::string &f #ifdef WIN32 if(unixFileName[1] == ':') // absolute path + fileName = "file:///" + unixFileName; #else if(unixFileName[0] == '/') // absolute path -#endif fileName = "file://" + unixFileName; +#endif else // relative path fileName = unixFileName; @@ -108,10 +110,11 @@ osgDB::ReaderWriter::ReadResult ReaderWriterVRML2::readNode(const std::string &f return ReadResult::FILE_NOT_HANDLED; } else { - osg::ref_ptr osg_root = new osg::MatrixTransform(osg::Matrix(1, 0, 0, 0, - 0, 0, 1, 0, - 0, -1, 0, 0, - 0, 0, 0, 1)); + osg::ref_ptr osg_root = + new osg::MatrixTransform(osg::Matrix( 1, 0, 0, 0, + 0, 0, 1, 0, + 0, -1, 0, 0, + 0, 0, 0, 1)); for (unsigned i = 0; i < mfn.size(); i++) { openvrml::node *vrml_node = mfn[i].get(); @@ -147,7 +150,8 @@ osg::ref_ptr ReaderWriterVRML2::convertFromVRML(openvrml::node *obj) osg_group->addChild(convertFromVRML(node).get()); } } - } catch (openvrml::unsupported_interface &e) + } + catch (openvrml::unsupported_interface&) { // no children } @@ -173,7 +177,8 @@ osg::ref_ptr ReaderWriterVRML2::convertFromVRML(openvrml::node *obj) osg_m->addChild(convertFromVRML(node).get()); } } - } catch (openvrml::unsupported_interface &e) + } + catch (openvrml::unsupported_interface&) { // no children } @@ -209,12 +214,11 @@ osg::ref_ptr ReaderWriterVRML2::convertFromVRML(openvrml::node *obj) // get array of vertex coordinate_nodes { - const openvrml::field_value & fv = vrml_ifs->field("coord"); - const openvrml::sfnode &sfn = dynamic_cast(fv); - openvrml::vrml97_node::coordinate_node *vrml_coord_node = - dynamic_cast(sfn.value.get()); + const openvrml::field_value& fv = vrml_ifs->field("coord"); + const openvrml::sfnode& sfn = dynamic_cast(fv); + openvrml::vrml97_node::coordinate_node* vrml_coord_node = dynamic_cast(sfn.value.get()); - const std::vector &vrml_coord = vrml_coord_node->point(); + const std::vector& vrml_coord = vrml_coord_node->point(); osg::ref_ptr osg_vertices = new osg::Vec3Array(); unsigned i; @@ -236,15 +240,23 @@ osg::ref_ptr ReaderWriterVRML2::convertFromVRML(openvrml::node *obj) for (i = 0; i < vrml_coord_index.value.size(); i++) { int index = vrml_coord_index.value[i]; - if (index == -1) { - ((osg::DrawArrayLengths*) osg_geom->getPrimitiveSet(0))->push_back(num_vert); + if (index == -1) + { + static_cast(osg_geom->getPrimitiveSet(0))->push_back(num_vert); num_vert = 0; - } else { + } + else + { osg_vert_index->push_back(index); - num_vert ++; + ++num_vert; } } - + if (num_vert) + { + //GvdB: Last coordIndex wasn't -1 + static_cast(osg_geom->getPrimitiveSet(0))->push_back(num_vert); + } + osg_geom->setVertexIndices(osg_vert_index.get()); } @@ -293,14 +305,13 @@ osg::ref_ptr ReaderWriterVRML2::convertFromVRML(openvrml::node *obj) // get array of normals per vertex (if specified) { - const openvrml::field_value &fv = vrml_ifs->field("normal"); - const openvrml::sfnode &sfn = dynamic_cast(fv); - openvrml::vrml97_node::normal_node *vrml_normal_node = - dynamic_cast(sfn.value.get()); + const openvrml::field_value& fv = vrml_ifs->field("normal"); + const openvrml::sfnode& sfn = dynamic_cast(fv); + openvrml::vrml97_node::normal_node* vrml_normal_node = dynamic_cast(sfn.value.get()); if (vrml_normal_node != 0) // if no normals, node is NULL pointer { - const std::vector &vrml_normal_coord = vrml_normal_node->vector(); + const std::vector& vrml_normal_coord = vrml_normal_node->vector(); osg::ref_ptr osg_normalcoords = new osg::Vec3Array(); @@ -313,22 +324,24 @@ osg::ref_ptr ReaderWriterVRML2::convertFromVRML(openvrml::node *obj) osg_geom->setNormalArray(osg_normalcoords.get()); // get array of normal indices - const openvrml::field_value &fv2 = vrml_ifs->field("normalIndex"); - const openvrml::mfint32 &vrml_normal_index = dynamic_cast(fv2); + const openvrml::field_value& fv2 = vrml_ifs->field("normalIndex"); + const openvrml::mfint32& vrml_normal_index = dynamic_cast(fv2); osg::ref_ptr osg_normal_index = new osg::IntArray(); - if(vrml_normal_index.value.size() > 0) + if (vrml_normal_index.value.size() > 0) { for (i = 0; i < vrml_normal_index.value.size(); i++) { int index = vrml_normal_index.value[i]; - if (index != -1) { + if (index != -1) + { osg_normal_index->push_back(index); } } osg_geom->setNormalIndices(osg_normal_index.get()); - } else + } + else // unspecified, use the coordIndex field osg_geom->setNormalIndices(osg_geom->getVertexIndices()); @@ -405,6 +418,100 @@ osg::ref_ptr ReaderWriterVRML2::convertFromVRML(openvrml::node *obj) { osg_stateset->setAttributeAndModes(new osg::CullFace(osg::CullFace::BACK)); } + + if (!osg_geom->getNormalArray()) + { +#if 0 + // GvdB: This is what I wanted to do, but got zero normals since the triangles were considered temporaries (?) + osgUtil::SmoothingVisitor().smooth(*osg_geom); +#else + // GvdB: So I ended up computing the smoothing normals myself. Also, I might add support for "creaseAngle" if a big need for it rises. + // However, for now I can perfectly live with the fact that all edges are smoothed despite the use of a crease angle. + osg::Vec3Array& coords = *static_cast(osg_geom->getVertexArray()); + assert(coords.size()); + + osg::Vec3Array* normals = new osg::Vec3Array(coords.size()); + + for (osg::Vec3Array::iterator it = normals->begin(); it != normals->end(); ++it) + { + (*it).set(0.0f, 0.0f, 0.0f); + } + + + osg::IntArray& indices = *static_cast(osg_geom->getVertexIndices()); + osg::DrawArrayLengths& lengths = *static_cast(osg_geom->getPrimitiveSet(0)); + int index = 0; + + for (osg::DrawArrayLengths::iterator it = lengths.begin(); it != lengths.end(); ++it) + { + assert(*it >= 3); + const osg::Vec3& v0 = coords[indices[index]]; + const osg::Vec3& v1 = coords[indices[index + 1]]; + const osg::Vec3& v2 = coords[indices[index + 2]]; + + osg::Vec3 normal = (v1 - v0) ^ (v2 - v0); + normal.normalize(); + + for (int i = 0; i != *it; ++i) + { + (*normals)[indices[index + i]] += normal; + } + + index += *it; + } + + assert(index == indices.size()); + + for(osg::Vec3Array::iterator it = normals->begin(); it != normals->end(); ++it) + { + (*it).normalize(); + } + + osg_geom->setNormalArray(normals); + osg_geom->setNormalIndices(osg_geom->getVertexIndices()); + osg_geom->setNormalBinding(osg::Geometry::BIND_PER_VERTEX); + +#endif + } + + + osg::DrawArrayLengths& lengths = *static_cast(osg_geom->getPrimitiveSet(0)); + + osg::DrawArrayLengths::iterator it = lengths.begin(); + if (it != lengths.end()) + { + switch (*it) + { + case 3: + while (++it != lengths.end() && *it == 3) + ; + + if (it == lengths.end()) + { + // All polys are triangles + osg::ref_ptr mesh = new osg::DrawArrays(osg::PrimitiveSet::TRIANGLES); + mesh->setCount(lengths.size() * 3); + osg_geom->removePrimitiveSet(0); + osg_geom->addPrimitiveSet(mesh.get()); + } + break; + + case 4: + while (++it != lengths.end() && *it == 4) + ; + + if (it == lengths.end()) + { + // All polys are quads + osg::ref_ptr mesh = new osg::DrawArrays(osg::PrimitiveSet::QUADS); + mesh->setCount(lengths.size() * 4); + osg_geom->removePrimitiveSet(0); + osg_geom->addPrimitiveSet(mesh.get()); + } + + break; + } + } } else if (openvrml::vrml97_node::box_node* vrml_box = dynamic_cast(vrml_geom)) { @@ -786,33 +893,45 @@ osg::ref_ptr ReaderWriterVRML2::convertFromVRML(openvrml::node *obj) dynamic_cast(vrml_material_node.get()); // std::cerr << "sfnode->Material OK" << std::endl << std::flush; - if (vrml_material != NULL) { - osg_mat->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4(vrml_material->ambient_intensity(), - vrml_material->ambient_intensity(), - vrml_material->ambient_intensity(), - 1.0)); - osg_mat->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4(vrml_material->diffuse_color().r(), - vrml_material->diffuse_color().g(), - vrml_material->diffuse_color().b(), - 1.0)); - osg_mat->setEmission(osg::Material::FRONT_AND_BACK, osg::Vec4(vrml_material->emissive_color().r(), - vrml_material->emissive_color().g(), - vrml_material->emissive_color().b(), - 1.0)); - osg_mat->setSpecular(osg::Material::FRONT_AND_BACK, osg::Vec4(vrml_material->specular_color().r(), - vrml_material->specular_color().g(), - vrml_material->specular_color().b(), - 1.0)); - - osg_mat->setTransparency(osg::Material::FRONT_AND_BACK, vrml_material->transparency() ); - //osg_stateset->setRenderingHint(osg::StateSet::TRANSPARENT_BIN); + if (vrml_material != NULL) + { + osg_mat->setAmbient(osg::Material::FRONT_AND_BACK, + osg::Vec4(vrml_material->ambient_intensity(), + vrml_material->ambient_intensity(), + vrml_material->ambient_intensity(), + 1.0)); + osg_mat->setDiffuse(osg::Material::FRONT_AND_BACK, + osg::Vec4(vrml_material->diffuse_color().r(), + vrml_material->diffuse_color().g(), + vrml_material->diffuse_color().b(), + 1.0)); + osg_mat->setEmission(osg::Material::FRONT_AND_BACK, + osg::Vec4(vrml_material->emissive_color().r(), + vrml_material->emissive_color().g(), + vrml_material->emissive_color().b(), + 1.0)); + osg_mat->setSpecular(osg::Material::FRONT_AND_BACK, + osg::Vec4(vrml_material->specular_color().r(), + vrml_material->specular_color().g(), + vrml_material->specular_color().b(), + 1.0)); osg_mat->setShininess(osg::Material::FRONT_AND_BACK, vrml_material->shininess() ); - //osg_mat->setColorMode(osg::Material::OFF); + if (vrml_material->transparency() > 0.0f) + { + osg_mat->setTransparency(osg::Material::FRONT_AND_BACK, vrml_material->transparency()); + osg_stateset->setMode(GL_BLEND, osg::StateAttribute::ON); + osg_stateset->setAttribute(new osg::Depth(osg::Depth::LESS, 0.0, 1.0, false)); // GvdB: transparent objects do not write depth + osg_stateset->setRenderingHint(osg::StateSet::TRANSPARENT_BIN); + } + else + { + osg_stateset->setMode(GL_BLEND, osg::StateAttribute::OFF); + osg_stateset->setRenderingHint(osg::StateSet::OPAQUE_BIN); + } osg_stateset->setAttributeAndModes(osg_mat.get()); - osg_stateset->setMode(GL_BLEND, osg::StateAttribute::ON); //bhbn }