OSG QuickStartGuide - eiichiromomma/CVMLAB GitHub Wiki

(OSG) Quick Start Guide

Quick Start Guideに沿ったメモ書き

教科書

OSGの基本(Chapter2あたりから)

メモリ管理等

  • root nodeからのツリー構造
  • メモリ管理はGCがあるのでroot nodeをdeleteするだけで連鎖反応で消える
    • 殆どのオブジェクトはリファレンスカウンタを持っている
    • smart pointerのosg::ref_ptr<>を使うこと
      • C++のレギュラーなポインタは使わない
      • ref(),unref()は直接使わない
      • get()でprivateなpointerを得る
      • valid()でtrueならnullでない
      • ref_ptrを返り値にしたい場合はreturn obj.get()とする

書籍のサンプルソースの一部

    //
    // OpenSceneGraph Quick Start Guide
    // http://www.lulu.com/content/767629
    // http://www.openscenegraph.com/osgwiki/pmwiki.php/Documentation/QuickStartGuide
    //
    // Simple Example, Basic Geode and Geometry class usage
    #include <osg/Geode>
    #include <osg/Geometry>
    
    osg::ref_ptr<osg::Node>
    createSceneGraph()
    {
        // Create an object to store geometry in.
        osg::ref_ptr<osg::Geometry> geom = new osg::Geometry;

        // Create an array of four vertices.
    #if 1
        // Using the push_back interface
        osg::ref_ptr<osg::Vec3Array> v = new osg::Vec3Array;
        geom->setVertexArray( v.get() );
        v->push_back( osg::Vec3( -1.f, 0.f, -1.f ) );
        v->push_back( osg::Vec3( 1.f, 0.f, -1.f ) );
        v->push_back( osg::Vec3( 1.f, 0.f, 1.f ) );
        v->push_back( osg::Vec3( -1.f, 0.f, 1.f ) );
    #else
        // Using resize() and operator[]().
        osg::ref_ptr<osg::Vec3Array> v = new osg::Vec3Array;
        geom->setVertexArray( v.get() );
        v->resize( 4 );
        (*v)[ 0 ] = osg::Vec3( -1.f, 0.f, -1.f );
        (*v)[ 1 ] = osg::Vec3( 1.f, 0.f, -1.f );
        (*v)[ 2 ] = osg::Vec3( 1.f, 0.f, 1.f );
        (*v)[ 3 ] = osg::Vec3( -1.f, 0.f, 1.f );
    #endif
    
        // Create an array of four colors.
        osg::ref_ptr<osg::Vec4Array> c = new osg::Vec4Array;
        geom->setColorArray( c.get() );
        geom->setColorBinding( osg::Geometry::BIND_PER_VERTEX );
        c->push_back( osg::Vec4( 1.f, 0.f, 0.f, 1.f ) );
        c->push_back( osg::Vec4( 0.f, 1.f, 0.f, 1.f ) );
        c->push_back( osg::Vec4( 0.f, 0.f, 1.f, 1.f ) );
        c->push_back( osg::Vec4( 1.f, 1.f, 1.f, 1.f ) );
    
        // Create an array for the single normal.
        osg::ref_ptr<osg::Vec3Array> n = new osg::Vec3Array;
        geom->setNormalArray( n.get() );
        geom->setNormalBinding( osg::Geometry::BIND_OVERALL );
        n->push_back( osg::Vec3( 0.f, -1.f, 0.f ) );
    
        // Draw a four-vertex quad from the stored data.
        geom->addPrimitiveSet(
            new osg::DrawArrays( osg::PrimitiveSet::QUADS, 0, 4 ) );
    
        // Add the Geometry (Drawable) to a Geode and return the Geode.
        osg::ref_ptr<osg::Geode> geode = new osg::Geode;
        geode->addDrawable( geom.get() );
        return geode.get();
    }

GeodeとGeometry

  • Vectorはpush_back()でストア、単品で宣言してもresize()で配列にできる

    osg::ref_ptrosg::Vec3Array v = new osg::Vec3Array; geom->setVertexArray(v.get()); v.resize(4); (*v)[0] = osg::Vec3(-1.f, 0.f, -1.f); (*v)[1] = ...

みたいな感じ

  • osg::Drawableは仮想基本クラス。直接扱うことはない。3つのサブクラスがある。
    • osg::DrawPixels - glDrawPixelsのラッパー
    • osg::ShapeDrawable - 円柱、球等のpredefinedなShapeへのアクセス
    • osg::Geometry - フレキシブルでジオメトリやレンダリングに用いる。最も使われる。
      • Vec3Array - setVertexArray(),setNormalArray() <-> glVertexPointer(), glNormalPointer()
      • Vec4Array - setColorArray() <-> glColorPointer()
    • setColorBinding(), setNormalBinding() - どう色と法線を扱うか。enumになっている
      • osg::Geometry::BIND_PER_VERTEX - 各頂点(ソースでは色に使ってる)
      • osg::Geometry::BIND_OVERALL - 共通(法線に使った)
    • addPrimitiveSet() - Geometryにどうレンダーすれば良いか教える。osg::PrimitiveSetを引数にするが、これは仮想基本クラス
      • osg::DrawArraysはPrimitiveSetの派生。glDrawArraysのラップみたいなもん osg::DrawArrays:DrawArrays(GLenum mode, GList first, GLsizei count)

と定義されるので、modeはGLのプリミティブでもosg::PrimitiveSet::POINTSのenumでも良い。firstはOSGが扱うエレメントの数。countは頂点の数。2,6なら

頂点 0 1 2 3 4 5 0 1 2 3 4 5
エレメント 0 0 0 0 0 0 1 1 1 1 1 1

って事か?

  • Geodeはレンダリングに使うGeometryをストアするためのleaf node。 osg::Nodeの派生。
    • Geode is short for "geometry node" (a node contains geometry)とある
    • いかなるgeometryもGeodeにattachされなければレンダリングできない
    • GeodeのaddDrawable()によってgeometryをGeodeにattachできる
      • Geode::addDrawable()はDrawableへのポインタが引数。geometryのget()でポインタを入れる

Group Nodes

Group NodesはReferencedおよびNodeからの派生。Transform, LOD, Switch等に派生する

  • nodeの殆どはGroupからの派生 = 殆どのnodeがChild Interfaceを持つ
    • std::vector<ref_ptr>にchildrenを持つ(子ノードに関するI/F)
      • addChild, removeChild, replaceChild, getNumChildren, containsNode
    • std::vector<Group*>に親リストを持つ
      • 通常は1つの親しか持たないが、同一の物を別の手法でレンダリングしたい場合などに複数となる
      • getParents, getParent, getNumParents

TransformNodes

Groupからの派生。仮想クラスでosg::MatrixTransformやosg::PositionAttitudeTransformへ派生

Matrix Transform Node

内部でMatrixを使う

  • MatrixはReferencedからの派生ではないのでローカルに消滅する値として扱う
  • OpenGLのように1次元16個で4x4でも表現可
  • m(0,1)みたいな指定も可
    • osg::Matrix mで宣言し、m.set(....)としてmt.setMatrix(m)のように指定する

PositionAttitudeTransform Node

位置ベクトル(Vec3)とクォータニオンを使う

  • osg::Quat - クォータニオン。Referencedからの派生ではないのでローカルに扱う
    • 回転軸+角度の指定でも、ヨー、ピッチ、ロールの軸と回転角の指定でも作れる

LOD Node

Levels of Detail。Groupからの派生。

  • distanceのmaxとminを指定でき、外れると表示されない
    • addChildで指定
    • デフォルトでdistanceは視点からbounding volumeの中心
      • setCenterMode(osg::LOD::USER_DEFINED_CENTER)でsetCenter
  • distanceの代わりにピクセルサイズを基準にもできる(setRangeMode)

Switch Node

Groupからの派生。LOD Nodeのdistanceの代わりに直接的なスイッチがありtrue, falseで表示、非表示

Rendering State (Section 2.4)

OpenGLのパイプラインレンダリング(ライティング、ブレンディング、クリッピング、カラーマスク、カル、フォグ、デプス、ステンシル、ラスタライズなどなど)をサポート。StateSetクラスを使う

  • 頂点およびフラグメントshaderが使える

  • Node, Drawableへattachして使う

  • 冗長性の排除は自動的に最適化される

  • OpenGLの属性も利用可能

  • NodeやDrawableごとにstateが保持される

  • Referencedからの派生でもあるため、NodeやDrawableで余計なことを考えずに共有できる

  • 属性(Attributes)とモード(Modes)に分類される

    • Attributes:レンダリングの特徴量をコントロールする(フォグ、ブレンド等)
    • Modes:OpenGLのglEnable(), glDisableに対応する。(テクスチャ、ライティング) 要するにオンオフ
  • NodeかDrawableのgetOrCreateStateSet()でStateSetのポインタを取得して使う

  • 設定する属性のクラスはStateAttributeから派生

    • テクスチャだけは特別な扱いが必要
  • Attributeの設定はosg::StateSet::setAttribute()

  • Modeの設定はosg::StateSet::setMode()

  • いっぺんに両方設定するにはosg::StateSet::setAttributeAndModes()

    • ModeがデフォルトでオンのsetAttribute()みたいなもん
  • Stateの継承は子ノードがその項目を弄ってなければ行なわれる

    • osg::StateAttribute::OVERRIDE - とりあえず上書き
    • osg::StateAttribute::PROTECTED - 独自の属性は保護される
    • osg::StateAttribute::INHERIT - 子のstateは消去され常に親のstate を参照する

Texture Mapping

基本的な使い方

テクスチャ座標をgeometryに割り当て、texture attributeオブジェクトを作成し、テクスチャ用image dataをstoreする。そしてStateSetに適当なtexture attributeとmodeをsetする。

テクスチャ座標

  • Geometryはテクスチャ座標を設定できる
    • 当然対応するテクスチャunitを設定する必要もある
    • OSGはtexture unit valueをmulti textureのために使う
    • 座標はosg::Vec2Array
      • osg::Vec2をbushu_back()する
  • geom->setTexCoordArray(texture unit, Vec2Array)
  • ちなみにbindingについては常にbound per pixelなので宣言不要

Loading Images

  • osg::Texture2Dとosg::Imageが2Dテクスチャマッピングに必要
    • Texture2DはOpenGLテクスチャオブジェクトをmanageするStateAttribute
    • Imageはピクセルデータをmanageする
  • ファイルから2D画像を得るにはosgDBライブラリを使う
    • Imageオブジェクトを作って、ImageをTexture2Dにattachする役割 (P65にソース)

osgDB

readImageFIle()は新しいImageオブジェクトを作成し、ファイルを読みImageへstoreし、Imageオブジェクトを返す(詳細はI/Oの所)

  • Texture2D attributeを設定したらStateSetへattachする
  • この処理はメモリをガシガシ食うのでImageはReferencedから派生され、Texture2DはImageのref_ptr<>を保持する
    • メモリをカツカツに節約したい場合は、レンダーすると勝手に生成されるOpenGL managedなデータとImageオブジェクトの2つのうち、後者をreleaseすれば良い
      • デフォルトでは放置

TextureState

  • 中身は前述のnon-textureなstateとほぼ同じ
  • StateSetへattachするにはosg::StateSet::setTextureAttribute()
    • 第一引数はtexture unit, 第二はStateAttributeからの派生のtexture attribute
      • texture attributeにはTexture1D, Texture2D, Texture3D, TextureCubeMap, TextureREctangleとテクスチャ座標生成のosg::TexGenがある (P66参照)
  • モードはosg::StateSet::setTextureMode()
    • non-textureなmodeとほぼ同じ

Lighting

  • OpenGLのlightingを完全サポート
  • OpenGL同様に光源は見えない
    • bulbその他の物理的約束事はレンダーしない
  • shading効果は生成するが影(shadow)は作らない
    • NodeKitのosgShadowを使う

Lightを使うには?

  1. geometryの法線を設定する
  2. lightingを有効にし、その他のlighting stateを設定する
  3. 光源のpropertiesを設定し、シーングラフにattachする
  4. surface material propertiesを設定する
  • Chapter3のosgViewerライブラリを使う場合はGL_LIGHT0が定義済みなので注意

Normals

  • 性格なlightingには単位長を持った法線ベクトルが必要

    • Geodes and GEometry(2.2)で解説済み
  • 必ず正規化するのを忘れないこと

    • 変換処理をしているとnormalのscaleも変わってくる
    • StateSetでrescaleが望ましい
      • これはuniform scalingによる影響を受けた時のみ作用する
      • non uniformの場合はGL_NORMALIZEとするが、計算コストがかかるので極力避ける

    osg::StateSet* state = geode->getOrCreateStateSet(); state->setMode(GL_RESCALE_NORMAL, osg::StateAttribute::ON);

Lighting State

  • lightingを有効にして少なくとも1つは光源を用意する
  • osgviewerアプリではroot nodeのStateSetに設定している
  • P68のソースはroot nodeのStateSetに2つのライトを設定している
  • osg::LightModelStateAttributeでOpenGLのlightingの特性をコントロールする

Light Sources

  • osg::Lightをosg::LightSourceノードに加え、これをシーングラフに加える
  • 最大8子まで使用可 GL_LIGHT0〜7(OpenGLの実装に依存)
    • 応用的な方法はこのガイドでは述べない
  • setLightNum(2)とするとGL_LIGHT2になる
  • glLight()と同様に色々設定可能(P69)

シーンにLightを加えるには…

  1. LightSource nodeを作成
  2. LightをLightSourceに加える
  3. シーングラフにLightSourceをattach
  • どこのシーンに突っ込むかでLightの位置に影響する
    • LightSource nodeのあるレベルで位置変換の影響を受ける
    • よくやるのはMatrixTransformのchildとしてLightSourceをattachする

(P70 source)

Transformノードでのやり方と同様に変換されないようにもできる(2.3.3) osg::ref_ptrosg::LightSource ls = new osg::LightSource; ls->setReferenceFrame(osg::LightSource::ABSOLUTE_RF);

Material Properties

  • OpenGLのglMaterial()やglColorMaterial()と同様
  • Materialオブジェクトを作成し、パラメータ設定してからシーングラフにattachする
    • カラーモードは有効にしただけコストがかかるので、使わなければ勝手にOFFになる。setAttributeAndModels()は不要
⚠️ **GitHub.com Fallback** ⚠️