Hi again,
Well, I've been able to change the 48 small triangle strips per geometry
to a single DrawElements call, with naive code that just puts indices to
replicate what the strip is doing, i.e. 0 1 2 1 2 3 2 3 4 etc.
The result is a small but noticeable decrease in draw time. It's smaller
than I would have thought. Perhaps there would be an even better way
than the naive approach I'm using?
I'm attaching the code, see the part starting at #define
USE_TRIANGLE_STRIPS (which needs to be commented to use my changes).
Thanks,
J-S
--
______________________________________________________
Jean-Sebastien Guay [email protected]
http://www.cm-labs.com/
http://whitestar02.webhop.org/
/*
-------------------------------------------------------------------------------
| osgEphemeris - Copyright (C) 2007 Don Burns |
| |
| This library is free software; you can redistribute it and/or modify |
| it under the terms of the GNU Lesser General Public License as published |
| by the Free Software Foundation; either version 3 of the License, or |
| (at your option) any later version. |
| |
| This library is distributed in the hope that it will be useful, but |
| WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY |
| or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public |
| License for more details. |
| |
| You should have received a copy of the GNU Lesser General Public License |
| along with this software; if not, write to the Free Software Foundation, |
| Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. |
| |
-------------------------------------------------------------------------------
*/
#include <osg/Geometry>
#include <osgEphemeris/Sphere.h>
using namespace osgEphemeris;
const double Sphere::_defaultRadius = 3476000.0 * 0.5; // diameter of moon
* 0.5 = radius of moon
Sphere::Sphere( double radius,
Sphere::TesselationResolution tr,
Sphere::Orientation orientation,
Sphere::Hemisphere whichHemisphere,
bool stc
)
{
_skyTexCoords = stc;
unsigned int nsectors = 4;
double latStep =
( tr == TessHigh ) ? 1.875 :
( tr == TessLow ) ? 15 : 7.5;
osg::ref_ptr<osg::Vec3Array> v = new osg::Vec3Array;
int R = 0;
for( unsigned int sector = 0; sector < nsectors; sector++ )
{
double off = double(sector) * 360.0/(double)(nsectors);
int div = 1;
v->push_back( osg::Vec3(0,0,radius));
for( double lat = latStep; lat <= 91.0; lat += latStep )
{
double dd = (360.0/double(nsectors))/(double)(div);
for( int i = 0; i <= div; i++ )
{
double lon = off + double(i) * dd;
double x = radius * cos(osg::DegreesToRadians(lon)) *
sin(osg::DegreesToRadians(lat));
double y = radius * sin(osg::DegreesToRadians(lon)) *
sin(osg::DegreesToRadians(lat));
double z = radius * cos(osg::DegreesToRadians(lat));
v->push_back( osg::Vec3(x,y,z));
}
div++;
if( sector == 0 )
R++;
}
}
for( int hemisphere = 0; hemisphere < 2; hemisphere++ )
{
if( !((1<<hemisphere) & whichHemisphere) )
continue;
osg::Geode *geode = new osg::Geode;
int iii = 0;
osg::ref_ptr<osg::Vec3Array> coords = new osg::Vec3Array;
osg::ref_ptr<osg::Vec3Array> normals = new osg::Vec3Array;
osg::ref_ptr<osg::Vec2Array> tcoords = new osg::Vec2Array;
for( unsigned int sector = 0; sector < nsectors; sector++ )
{
int len = 3;
int ii[] = { 1, 0 };
int toggle = 0;
for( int j = 0; j < R; j++ )
{
osg::ref_ptr<osg::Vec3Array> tarray = new osg::Vec3Array;
for( int i = 0; i < len; i++ )
{
int index = iii + ii[toggle];
tarray->push_back( (*v)[index] );
ii[toggle]++;
toggle = 1 - toggle;
}
if( hemisphere == 0 )
{
if( orientation == InnerOrientation )
{
for( unsigned int n = 0; n < tarray->size(); n++ )
{
osg::Vec3 v = (*tarray)[n];
coords->push_back( v );
v.normalize();
v *= -1;
normals->push_back( v );
tcoords->push_back( makeTexCoord(v, sector) );
}
}
else
{
for( int n = tarray->size() - 1; n >= 0 ; n-- )
{
osg::Vec3 v = (*tarray)[n];
coords->push_back( v );
v.normalize();
normals->push_back( v );
tcoords->push_back( makeTexCoord(v, sector) );
}
}
}
else
{
if( orientation == InnerOrientation )
{
for( int n = tarray->size() - 1; n >= 0 ; n-- )
{
osg::Vec3 v = (*tarray)[n];
v[2] *= -1.0;
coords->push_back( v );
v.normalize();
v *= -1;
normals->push_back( v );
tcoords->push_back( makeTexCoord(v, sector) );
}
}
else
{
for( unsigned int n = 0; n < tarray->size(); n++ )
{
osg::Vec3 v = (*tarray)[n];
v[2] *= -1.0;
coords->push_back( v );
v.normalize();
normals->push_back( v );
tcoords->push_back( makeTexCoord(v, sector) );
}
}
}
toggle = 1 - toggle;
len += 2;
}
iii += ii[0];
}
int index = 0;
for( unsigned int sector = 0; sector < nsectors; sector++ )
{
osg::ref_ptr<osg::Vec4Array> colors = new osg::Vec4Array;
colors->push_back( osg::Vec4( 1.0, 1.0, 1.0,1.0 ));
osg::ref_ptr<osg::Geometry> geometry = new osg::Geometry;
geometry->setVertexArray( coords.get() );
geometry->setTexCoordArray( 0, tcoords.get() );
geometry->setNormalArray( normals.get() );
geometry->setNormalBinding( osg::Geometry::BIND_PER_VERTEX );
geometry->setColorArray( colors.get() );
geometry->setColorBinding( osg::Geometry::BIND_OVERALL );
//#define USE_TRIANGLE_STRIPS
#ifdef USE_TRIANGLE_STRIPS
int len = 3;
for( int i = 0; i < R; i++ )
{
geometry->addPrimitiveSet( new
osg::DrawArrays(osg::PrimitiveSet::TRIANGLE_STRIP, index, len ));
index += len;
len += 2;
}
#else
// Not sure R*R*3 is correct in for all possible values of R, but
it is for what I'm testing.
osg::DrawElementsUShort* primitiveSet = new
osg::DrawElementsUShort(osg::PrimitiveSet::TRIANGLES, R*R*3);
int len = 3;
int tri = 0;
for( int i = 0; i < R; i++ )
{
for (int v = 0; v < len-2; ++v)
{
if (v & 1)
{
(*primitiveSet)[tri*3+0] = index + v+0;
(*primitiveSet)[tri*3+1] = index + v+2;
(*primitiveSet)[tri*3+2] = index + v+1;
}
else
{
(*primitiveSet)[tri*3+0] = index + v+0;
(*primitiveSet)[tri*3+1] = index + v+1;
(*primitiveSet)[tri*3+2] = index + v+2;
}
++tri;
}
index += len;
len += 2;
}
geometry->addPrimitiveSet(primitiveSet);
#endif
geode->addDrawable( geometry.get() );
}
if( hemisphere == 0 )
{
_northernHemisphere = geode;
addChild( _northernHemisphere.get() );
}
else
{
_southernHemisphere = geode;
addChild( _southernHemisphere.get() );
}
}
}
osg::Vec2 Sphere::makeTexCoord(osg::Vec3 &normal, unsigned int sector)
{
double s = 0.0;
{
double a = atan2( normal[1], normal[0] );
if( a < 0.0 )
a += osg::PI*2;
a /= (2*osg::PI);
// Prevent wrapping of texcoord, which creates ugly seam
if(sector == 2 && a > 0.999)
a = 0.0;
s = a;
}
double t;
if( _skyTexCoords )
t = (1.0 + ((asin(normal[2]))/(osg::PI_2)));
else
t = (0.5 + ((asin(normal[2]))/(osg::PI)));
return osg::Vec2( s, t );
}
double Sphere::getDefaultRadius()
{
return _defaultRadius;
}
SphereLOD::SphereLOD( double radius,
Sphere::Orientation orientation,
Sphere::Hemisphere hemisphere )
{
addChild( new Sphere( radius, Sphere::TessHigh, orientation, hemisphere ) );
addChild( new Sphere( radius, Sphere::TessNormal, orientation, hemisphere )
);
addChild( new Sphere( radius, Sphere::TessLow, orientation, hemisphere ) );
setRange( 0, 0.0, 10*radius );
setRange( 1, 10*radius, 50*radius );
setRange( 2, 50*radius, 1e12*radius );
}
_______________________________________________
osg-users mailing list
[email protected]
http://lists.openscenegraph.org/listinfo.cgi/osg-users-openscenegraph.org