Ответ 1
Предостережение: Я не эксперт по OSG. Но я сделал некоторые исследования.
OSG требует, чтобы все грани определялись в порядке против часовой стрелки, так что отбраковка задней поверхности может отклонять грани, которые "обращены в сторону". Код, который вы используете для создания сферы, не генерирует все грани в порядке против часовой стрелки.
Вы можете сделать это несколькими способами:
- Отрегулируйте, как код генерирует грани, вставив порядок CCW граней.
- Снова удвоить свою модель и вставить каждую грань дважды, один раз с вершинами на каждой грани в их текущем порядке и один раз с вершинами в обратном порядке.
Вариант 1 выше ограничивает общее количество полигонов тем, что необходимо. Вариант 2 даст вам сферу, которая видна вне сферы и внутри.
Чтобы реализовать вариант 2, вам просто нужно изменить этот цикл из кода, с которым вы связались:
indices.resize(rings * sectors * 4);
std::vector<GLushort>::iterator i = indices.begin();
for(r = 0; r < rings-1; r++)
for(s = 0; s < sectors-1; s++) {
*i++ = r * sectors + s;
*i++ = r * sectors + (s+1);
*i++ = (r+1) * sectors + (s+1);
*i++ = (r+1) * sectors + s;
}
Снова удвоить набор квадов:
indices.resize(rings * sectors * 8);
std::vector<GLushort>::iterator i = indices.begin();
for(r = 0; r < rings-1; r++)
for(s = 0; s < sectors-1; s++) {
*i++ = r * sectors + s;
*i++ = r * sectors + (s+1);
*i++ = (r+1) * sectors + (s+1);
*i++ = (r+1) * sectors + s;
*i++ = (r+1) * sectors + s;
*i++ = (r+1) * sectors + (s+1);
*i++ = r * sectors + (s+1);
*i++ = r * sectors + s;
}
Это действительно решение "большего молотка".
Лично мне трудно понять, почему исходный цикл недостаточно; интуитивно понятный мой путь через геометрию, он чувствует, что он уже генерирует лица CCW, потому что каждое последующее кольцо выше предыдущего, а каждый последующий сектор - CCW вокруг поверхности сферы из предыдущего. Таким образом, исходный порядок должен быть CCW по отношению к лицу, ближайшему к зрителю.
EDIT Используя код OpenGL, который вы связали ранее, и учебник OSG, который вы связали сегодня, я собрал то, что, по моему мнению, является правильной программой для создания osg::Geometry
/osg::Geode
для сферы. У меня нет возможности протестировать следующий код, но, проверяя его, он выглядит корректно или, по крайней мере, в значительной степени правилен.
#include <vector>
class SolidSphere
{
protected:
osg::Geode sphereGeode;
osg::Geometry sphereGeometry;
osg::Vec3Array sphereVertices;
osg::Vec3Array sphereNormals;
osg::Vec2Array sphereTexCoords;
std::vector<osg::DrawElementsUInt> spherePrimitiveSets;
public:
SolidSphere(float radius, unsigned int rings, unsigned int sectors)
{
float const R = 1./(float)(rings-1);
float const S = 1./(float)(sectors-1);
int r, s;
sphereGeode.addDrawable( &sphereGeometry );
// Establish texture coordinates, vertex list, and normals
for(r = 0; r < rings; r++)
for(s = 0; s < sectors; s++)
{
float const y = sin( -M_PI_2 + M_PI * r * R );
float const x = cos(2*M_PI * s * S) * sin( M_PI * r * R );
float const z = sin(2*M_PI * s * S) * sin( M_PI * r * R );
sphereTexCoords.push_back( osg::Vec2(s*R, r*R) );
sphereVertices.push_back ( osg::Vec3(x * radius,
y * radius,
z * radius) );
sphereNormals.push_back ( osg::Vec3(x, y, z) );
}
sphereGeometry.setVertexArray ( &spehreVertices );
sphereGeometry.setTexCoordArray( &sphereTexCoords );
// Generate quads for each face.
for(r = 0; r < rings-1; r++)
for(s = 0; s < sectors-1; s++)
{
spherePrimitiveSets.push_back(
DrawElementUint( osg::PrimitiveSet::QUADS, 0 )
);
osg::DrawElementsUInt& face = spherePrimitiveSets.back();
// Corners of quads should be in CCW order.
face.push_back( (r + 0) * sectors + (s + 0) );
face.push_back( (r + 0) * sectors + (s + 1) );
face.push_back( (r + 1) * sectors + (s + 1) );
face.push_back( (r + 1) * sectors + (s + 0) );
sphereGeometry.addPrimitveSet( &face );
}
}
osg::Geode *getGeode() const { return &sphereGeode; }
osg::Geometry *getGeometry() const { return &sphereGeometry; }
osg::Vec3Array *getVertices() const { return &sphereVertices; }
osg::Vec3Array *getNormals() const { return &sphereNormals; }
osg::Vec2Array *getTexCoords() const { return &sphereTexCoords; }
};
Вы можете использовать методы getXXX
для получения различных фрагментов. Я не видел, как привязать нормали поверхности к чему-либо, но я храню их в Vec2Array. Если у вас есть для них использование, они вычисляются и сохраняются и ждут, когда они будут подключены к чему-то.