a

Câu hỏi Tạo một Sphere (sử dụng osg :: Geometry) trong OpenSceneGraph


Tôi đã dành khá nhiều thời gian để làm việc này, nhưng Sphere của tôi sẽ không hiển thị.
Sử dụng đoạn mã sau đây để thực hiện chức năng của tôi:
Tạo hình cầu 3D trong Opengl bằng Visual C ++ 

Và phần còn lại là OSG đơn giản với osg :: Hình học.
(Lưu ý: Không ShapeDrawable, vì bạn không thể triển khai các hình dạng tùy chỉnh bằng cách sử dụng.)
Thêm đỉnh, normals, texcoords vào VecArrays.

Cho một, Tôi nghi ngờ một cái gì đó không đúng, như đối tượng đã lưu của tôi là một nửa trống rỗng.
Có cách nào để chuyển đổi mô tả hiện tại thành OSG?
Lý do? Tôi muốn hiểu cách tạo đối tượng sau này.
Thật vậy, nó được liên kết với một bài tập sau, nhưng hiện tại tôi chỉ đang chuẩn bị trước.

Sidenote: Vì tôi phải thực hiện nó mà không có chỉ mục, tôi đã bỏ chúng ra.
Nhưng xi lanh của tôi chỉ hiển thị tốt mà không có chúng.


12
2017-12-06 20:56


gốc


Xin chào mọi cơ hội bạn có thể đăng mẫu mã nhỏ? Nó sẽ giúp chúng tôi giúp bạn :) - GMasucci
@GMasucci Tôi nghĩ về nó, nhưng sau đó tôi đã bỏ ý tưởng khi OSG có một cú pháp thực sự đơn giản. Tôi sẽ thêm một số mã vào ngày mai. - Shiki
Bạn sẽ chia sẻ một số mã với chúng tôi? - Joe Z
@ JoeZ - Đây là một mẫu. trac.openscenegraph.org/projects/osg//wiki/Support/Tutorials/… (Tôi vừa tạo một hàm đẩy dữ liệu vào mảng, và sau đó hiển thị quad, không có gì lớn.) - Shiki
Đối với tất cả những người quan tâm: Tìm thấy một cách tuyệt vời để tạo ra hình dạng, chỉ đơn giản bằng cách sử dụng phương trình tham số của họ. Tôi sẽ đăng mã của tôi như là câu trả lời của riêng tôi. Hy vọng nó sẽ giúp mọi người tìm hiểu điều gì đó mới mẻ. - Shiki


Các câu trả lời:


Caveat: Tôi không phải là chuyên gia về OSG. Nhưng, tôi đã làm một số nghiên cứu.

OSG yêu cầu tất cả các khuôn mặt phải được xác định theo thứ tự ngược chiều kim đồng hồ, do đó việc tách khuôn mặt có thể từ chối các khuôn mặt "quay mặt ra". Mã bạn đang sử dụng để tạo hình cầu không tạo ra tất cả các khuôn mặt theo thứ tự ngược chiều kim đồng hồ.

Bạn có thể tiếp cận điều này theo một vài cách:

  1. Điều chỉnh cách mã tạo khuôn mặt, bằng cách chèn thứ tự khuôn mặt CCW.
  2. Nhân đôi mô hình của bạn và chèn từng khuôn mặt hai lần, một lần với các đỉnh trên mỗi khuôn mặt theo thứ tự hiện tại của chúng và một lần với các đỉnh theo thứ tự ngược lại.

Tùy chọn 1 ở trên sẽ giới hạn tổng số đa giác của bạn thành số cần thiết. Tùy chọn 2 sẽ cung cấp cho bạn một hình cầu có thể nhìn thấy từ bên ngoài hình cầu cũng như bên trong.

Để thực hiện Tùy chọn 2, bạn chỉ cần sửa đổi vòng lặp này từ mã bạn đã liên kết với:

    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;
        }

Tăng gấp đôi bộ tứ như vậy:

    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;
        }

Đó thực sự là giải pháp "búa lớn hơn".

Cá nhân, tôi đang gặp khó khăn trong việc tìm ra lý do tại sao vòng lặp ban đầu không đủ; intuiting theo cách của tôi thông qua các hình học, nó cảm thấy như nó đã tạo ra khuôn mặt CCW, bởi vì mỗi vòng liên tiếp là trên trước đó, và mỗi lĩnh vực liên tiếp là CCW xung quanh bề mặt của hình cầu từ trước đó. Vì vậy, bản thân thứ tự gốc nên là CCW đối với khuôn mặt gần người xem nhất.


CHỈNH SỬA  Sử dụng mã OpenGL mà bạn đã liên kết trước đây và hướng dẫn OSG bạn đã liên kết hôm nay, tôi đã tập hợp những gì tôi nghĩ là một chương trình chính xác để tạo osg::Geometry / osg::Geode cho hình cầu. Tôi không có cách nào để kiểm tra mã sau đây, nhưng kiểm tra bàn, nó có vẻ chính xác hoặc ít nhất là chính xác.

#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; }

};

Bạn có thể dùng getXXX phương pháp để có được các phần khác nhau. Tôi không thấy làm thế nào để móc các chỉ tiêu bề mặt lên bất cứ thứ gì, nhưng tôi lưu trữ chúng trong một Vec2Array. Nếu bạn có một sử dụng cho họ, họ đang tính toán và lưu trữ và chờ đợi để được nối với một cái gì đó.


6
2017-12-11 13:30



Vấn đề với điều này là chúng tôi không sử dụng (AFAIK) chỉ số trong OSG. Điều này làm cho một kim tự tháp ví dụ: trac.openscenegraph.org/projects/osg//wiki/Support/Tutorials/… . Hình dạng này cũng chỉ dựa trên các đỉnh ... Làm thế nào để tôi thành hình dạng? - Shiki
Vì vậy, vấn đề là, chúng tôi sử dụng Vertices (và Vec3Array cho điều đó), vì vậy bạn thậm chí không thể đẩy 4 chỉ số ở đó. Có lẽ tôi hoàn toàn mất tích điểm ở đây. Nếu có, vui lòng giải thích. - Shiki
Ví dụ này cho thấy đẩy các chỉ số đến đỉnh. Đó là gì pyramidBase->push_back() đang làm. Họ đẩy một số đỉnh, và sau đó họ bắt đầu xác định khuôn mặt về các chỉ số vào các đỉnh đó. - Joe Z
@Shiki: Tôi đã chỉnh sửa bài đăng của mình để cung cấp mã OSG. Cho tôi biết làm thế nào nó đi. - Joe Z
Đây là những gì xuất khẩu .obj trông giống như: pastebin.com/GVAkLM5n | Và đây là kết quả nửa quả cầu. Tôi đã không tạo ra một lớp như mã đó có vấn đề nhiều hơn mà cần phải được cố định. Đây là: i.imgur.com/a0p2fGN.jpg - Shiki


Cuộc gọi mã đó glutSolidSphere() để vẽ một hình cầu, nhưng nó không có ý nghĩa để gọi nó nếu ứng dụng của bạn không sử dụng GLUT để hiển thị cửa sổ với ngữ cảnh 3D.

Có một cách khác để vẽ hình cầu dễ dàng, đó là bằng cách gọi gluSphere() (bạn có thể đã cài đặt GLU):

khoảng trống gluSphere(GLUquadric * quad,                   GLdouble bán kính,                   GLint lát,                   GLint ngăn xếp);

Thông số

quad - Chỉ định đối tượng quadrics (được tạo bằng gluNewQuadric).

bán kính - Chỉ định bán kính của hình cầu.

lát - Chỉ định số phân khu xung quanh trục z (tương tự   đến các dòng kinh độ).

ngăn xếp - Chỉ định số lượng phân khu dọc theo trục z (tương tự   đến các đường vĩ độ).

Sử dụng:

// 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);

Nó có thể khôn ngoan hơn để di chuyển gluNewQuadric() gọi hàm tạo của lớp của bạn vì nó chỉ cần được cấp phát một lần và chuyển cuộc gọi đến gluDeleteQuadric() để destructor của lớp.


3
2017-12-16 20:11



Bạn không thể xuất hình học như vậy trong OSG (theo như tôi biết), và câu hỏi là về OSG thuần túy (thuần túy như nó được). Tuy nhiên, câu trả lời là khá hữu ích cho những người có thể đi lang thang đến vùng đất của OSG. - Shiki
Bạn có thể có công cụ GLU trong OSG bằng cách kế thừa từ osg::Drawable và ghi đè drawImplementation() phương pháp. Trên thực tế bạn có thể có bất cứ thứ gì GL bạn muốn ở đó. Điều này được thực hiện trong ví dụ về NURBS Surface trong OpenSceneGraph 3 Cookbook. Nó thực sự là chậm tuy nhiên, trong trường hợp cụ thể đó. - Patrick K


@ JoeZ của câu trả lời là tuyệt vời, nhưng mã OSG có một số lỗi / thực hành xấu. Đây là mã được cập nhật. Nó đã được thử nghiệm và nó cho thấy một quả cầu rất đẹp.

    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;
    }

Thay đổi:

  • Các phần tử OSG được sử dụng trong mã bây giờ là các con trỏ thông minh1. Hơn nữa, các lớp học như Geode và Geometry có các trình phá hủy được bảo vệ, vì vậy cách duy nhất để khởi tạo chúng là thông qua phân bổ động.

  • Đã xóa spherePrimitiveSets vì nó không cần thiết trong phiên bản hiện tại của mã.

  • Tôi đặt mã trong một chức năng miễn phí, vì tôi không cần Sphere lớp trong mã của tôi. Tôi bỏ qua getters và các thuộc tính được bảo vệ. Chúng không cần thiết: nếu bạn cần truy cập, ví dụ, hình học, bạn có thể lấy nó qua: sphereGeode->getDrawable(...). Cũng vậy với phần còn lại của các thuộc tính.

[1] Xem Quy tắc ngón tay cái # 1  đây. Đó là một chút cũ nhưng lời khuyên vẫn duy trì.


0
2017-11-03 08:37