我花了很长时间才开始工作,但是我的Sphere不会显示
使用以下代码来实现我的功能:
Creating a 3D sphere in Opengl using Visual C++
其余的简单的OSG , osg :: Geometry 。
(注意:不是ShapeDrawable,因为您无法使用它实现自定义形状。)
将顶点,法线,texcoords添加到VecArrays中。
一个人我怀疑行为不端,因为我保存的物品是半空的。
有没有办法将现有描述转换为OSG?
原因?我想了解如何在以后创建对象。
事实上,它与后来的任务有关,但目前我只是预先准备。
Sidenote :由于我必须在没有索引的情况下制作它,所以我把它们排除了 但是没有它我的圆筒显示得很好。
答案 0 :(得分:6)
OSG要求以逆时针顺序定义所有面,以便背面剔除可以拒绝“面向”的面。您用于生成球体的代码不会以逆时针顺序生成所有面。
你可以通过几种方式解决这个问题:
上面的选项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。
编辑使用您之前链接的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中。如果您对它们有用,那么它们就会被计算和存储,并等待被它们挂钩。
答案 1 :(得分:3)
该代码调用glutSolidSphere()
来绘制球体,但如果您的应用程序未使用GLUT来显示带有3D上下文的窗口,则调用它是没有意义的。
还有另一种方法可以轻松绘制球体,即通过调用gluSphere()
(您可能安装了GLU):
无效 gluSphere (GLUquadric * quad , GLdouble radius , GLint 切片, GLint 堆栈);
<强>参数强>
quad - 指定quadrics对象(使用gluNewQuadric创建)。
radius - 指定球体的半径。
slices - 指定z轴周围的细分数(类似 到经度线。)
stacks - 指定沿z轴的细分数(类似 到纬度线。)
<强>用法:强>
// If you also need to include glew.h, do it before glu.h
#include <glu.h>
GLUquadric* _quadratic = gluNewQuadric();
if (_quadratic == NULL)
{
std::cerr << "!!! Failed gluNewQuadric" << std::endl;
return;
}
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0.0, 0.0, -5.0);
glColor3ub(255, 97, 3);
gluSphere(_quadratic, 1.4f, 64, 64);
glFlush();
gluDeleteQuadric(_quadratic);
将gluNewQuadric()
调用移动到类的构造函数可能更明智,因为它只需要分配一次,并将调用移到gluDeleteQuadric()
到类的析构函数。
答案 2 :(得分:0)
@ JoeZ的答案非常好,但OSG代码有一些错误/不良做法。这是更新的代码。它已经过测试,它显示了一个非常好的球体。
osg::ref_ptr<osg::Geode> buildSphere( const double radius,
const unsigned int rings,
const unsigned int sectors )
{
osg::ref_ptr<osg::Geode> sphereGeode = new osg::Geode;
osg::ref_ptr<osg::Geometry> sphereGeometry = new osg::Geometry;
osg::ref_ptr<osg::Vec3Array> sphereVertices = new osg::Vec3Array;
osg::ref_ptr<osg::Vec3Array> sphereNormals = new osg::Vec3Array;
osg::ref_ptr<osg::Vec2Array> sphereTexCoords = new osg::Vec2Array;
float const R = 1. / static_cast<float>( rings - 1 );
float const S = 1. / static_cast<float>( sectors - 1 );
sphereGeode->addDrawable( sphereGeometry );
// Establish texture coordinates, vertex list, and normals
for( unsigned int r( 0 ); r < rings; ++r ) {
for( unsigned int 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 ( sphereVertices );
sphereGeometry->setTexCoordArray( 0, sphereTexCoords );
// Generate quads for each face.
for( unsigned int r( 0 ); r < rings - 1; ++r ) {
for( unsigned int s( 0 ); s < sectors - 1; ++s ) {
osg::ref_ptr<osg::DrawElementsUInt> face =
new osg::DrawElementsUInt( osg::PrimitiveSet::QUADS,
4 )
;
// 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->addPrimitiveSet( face );
}
}
return sphereGeode;
}
<强>的变化:强>
代码中使用的OSG元素现在是智能指针 1 。此外,像Geode
和Geometry
这样的类的析构函数受到保护,因此实例化它们的唯一方法是通过动态分配。
删除了spherePrimitiveSets
,因为当前版本的代码中不需要它。
我把代码放在一个自由函数中,因为我的代码中不需要Sphere
类。我省略了getters
和受保护的属性。它们不是必需的:如果您需要访问几何体,您可以通过以下方式获取它:sphereGeode->getDrawable(...)
。其余属性也是如此。
[1]参见经验法则#1 here。这有点旧,但建议仍然存在。