2014年5月28日水曜日

OgreのBasic Tutorial 2をやってみた

今回はチュートリアルの2回目(http://www.ogre3d.org/tikiwiki/tiki-index.php?page=Basic+Tutorial+2&structure=Tutorials)をやってみた。

カメラ、光源、影に関する話。カメラは先走って前のチュートリアルでもちょっと触った。

カメラ

カメラは3次元空間のシーンの中で実際に画面に描画される範囲を指定するもので、iPhone用のテンプレートでは、OgreFramework::initOgre(...)の中で次のように生成されている。


m_pCamera = m_pSceneMgr->createCamera("Camera"); m_pCamera->setPosition(Vector3(0, 60, 160)); m_pCamera->lookAt(Vector3(0, 0, 0)); m_pCamera->setNearClipDistance(1); : m_pCamera->setAspectRatio(Real(m_pViewport->getActualWidth()) / Real(m_pViewport->getActualHeight()));

シーンマネージャのcreateCamera(...)でカメラのインスタンスを生成し、生成したカメラの位置をsetPosition(...)で指定し、カメラが見ている場所をlookAt(...)で指定している。

setNearClipDistance(...)は、カメラから見えている範囲で、実際に描画する一番手前の位置を指定している。一番奥の位置を指定するための、setFarClipDistance(...)というメソッドもある。

Camera

ちなみに、setNearClipDistance(...)の引数を160にしてみると、こうなった。

Ogre cut

ニアクリップがOgreの顔の辺りになったので一部が表示されなくなった。

setAspectRatio(...)は、画角(縦と横の比率)を指定するもので、描画先となるビューポートの比率と合わせておく必要がある。上の指定だとちゃんと

Ogre port

のように表示されるが、これを


m_pCamera->setAspectRatio(Real(m_pViewport->getActualWidth()) * 2 / Real(m_pViewport->getActualHeight()));

とすると、

Ogre thin

のようになってしまう。

チュートリアルの1をやった時にiPhoneを横向きにしたら、Ogreの顔がでろ〜んとなったのも、iPhoneの描画先のサイズとカメラの画角が合わなくなったからだと思う。iPhoneの回転のイベントで画角(若しくはビューポートの方?)を合わせてやればよさそう。

光源と影

次は、3Dシーンにリアリティと臨場感を与えてくれる光源と影の話

Ogreでは、次の3種類の影が標準で使える。

  1. Modulative Texture Shadows(乗算式テクスチャシャドー?)
  2. Modulative Stencil Shadows(乗算式ステンシルシャドー?)
  3. Additive Stencil Shadows(加算式ステンシルシャドー?)

仕組みについてはよく分からないので割愛。最も計算コストが高いのが、1. 次が3.で、2.が一番安上がりだけど精度も落ちるとのこと。

とりあえず、チュートリアルのcreateScene(...)の内容をほぼそのまま(シーンマネージャの参照先だけiPhone用のテンプレートに合わせて変更)使ってみる。


DemoApp::setupDemoScene() { Ogre::SceneManager *sceneMgr = OgreFramework::getSingletonPtr()->m_pSceneMgr; sceneMgr->setAmbientLight(Ogre::ColourValue(0, 0, 0)); sceneMgr->setShadowTechnique(Ogre::SHADOWTYPE_STENCIL_ADDITIVE); Ogre::Entity* entNinja = sceneMgr->createEntity("Ninja", "ninja.mesh"); entNinja->setCastShadows(true); sceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(entNinja); Ogre::Plane plane(Ogre::Vector3::UNIT_Y, 0); Ogre::MeshManager::getSingleton().createPlane("ground", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, plane, 1500, 1500, 20, 20, true, 1, 5, 5, Ogre::Vector3::UNIT_Z); Ogre::Entity* entGround = sceneMgr->createEntity("GroundEntity", "ground"); sceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(entGround); entGround->setMaterialName("Examples/Rockwall"); entGround->setCastShadows(false); }

今回はモデルとしてOgreの代わりに忍者を使っている。これはテンプレートから作成したプロジェクトには含まれていないけど、SDKの中にそれっぽいのがあったのでプロジェクトにコピーしてみた。

Ninja copy

また、Examples.materialの中の忍者の設定をみると、テクスチャとしてnskingr.jpgが指定されているので、これもSDKからプロジェクトへコピー。

Ninja texture

忍者を立たせる平面を、Ogre::MeshManager::getSingleton().createPlane(...)で作っているが、これのエンティティに設定しているマテリアル、"Examples/Rockwall"も、テクスチャとして"rockwall.tga"を使っているので、同じくこれもSDKからプロジェクトへコピー

Rockwall copy

Ogre::EntityのsetCastShadows(...)で影を他の物体へ投影するかどうかを指定する。忍者は影を投影し、平面は投影しない設定にしている。影の生成は負荷のかかる処理なので不要なら無効にした方がいいらしい。

ひとまず実行してみる。

Ninja silhouette

暗っ!

環境光を真っ暗(Ogre::ColourValue(0, 0, 0))にしたので当然といえば当然。しかし、忍者らしき怪しい黒い人影は表示されている。

ということで次は光源を配置する。

Ogreでは、次の3種類の光源が標準で使える。

  1. Point(点光源)…光源の周りを均等に照らす。リアル世界でいうと暗闇をぽつんと照らす豆電球をイメージすると分かりやすい。
  2. Spotlight(スポットライト)…懐中電灯の様に特定の方向に向かって照らす光源。位置の他、方向や照らす範囲(角度)等を指定する。
  3. Directional(指向性光源)…太陽や月の光のように一定方向から均等に照らす。

チュートリアルの内容どおり、光源を配置する処理をDemoApp::setupDemoScene()に追加する。


: Ogre::Light* pointLight = sceneMgr->createLight("pointLight"); pointLight->setType(Ogre::Light::LT_POINT); pointLight->setPosition(Ogre::Vector3(0, 150, 250)); pointLight->setDiffuseColour(1.0, 0.0, 0.0); pointLight->setSpecularColour(1.0, 0.0, 0.0); Ogre::Light* directionalLight = sceneMgr->createLight("directionalLight"); directionalLight->setType(Ogre::Light::LT_DIRECTIONAL); directionalLight->setDiffuseColour(Ogre::ColourValue(.25, .25, 0)); directionalLight->setSpecularColour(Ogre::ColourValue(.25, .25, 0)); directionalLight->setDirection(Ogre::Vector3( 0, -1, 1 )); Ogre::Light* spotLight = sceneMgr->createLight("spotLight"); spotLight->setType(Ogre::Light::LT_SPOTLIGHT); spotLight->setDiffuseColour(0, 0, 1.0); spotLight->setSpecularColour(0, 0, 1.0); spotLight->setDirection(-1, -1, 0); spotLight->setPosition(Ogre::Vector3(300, 300, 0)); spotLight->setSpotlightRange(Ogre::Degree(35), Ogre::Degree(50));

ポイントライト、点光源、平行光源を1つづつ配置して、光の色の設定などしている。"diffuse colour"(colourはcolorのイギリス式綴り)は、拡散光のことで物体を一様に照らす光の色の成分。"specular colour"は、反射光のことで、光と視線の入射角によって変わる色の成分。反射光を使うことで、金属のようなつるつるした質感を表現できる。

とりあえず、実行してみる。

Ninja

平面は照らされたけど、忍者はまだ少し暗い。それにどうも影が投影されていない。

カメラの位置を変えてみる。


m_pCamera->setPosition(Vector3(100, 200, -200));

Ninja2

やはり、影が投影されていない。チュートリアルによるとこの時点で影が投影されるはずなんだけど...

コンソールをみると「このデバイスはハードウェアステンシルに対応していない」といった内容のログが表示されていた。

Warning

ググってみたら、Ogreのフォーラムで質問がされていた。どうも、iPhoneでは、ステンシルシャドーが使えないみたい。ハード的には対応しているけどソースの修正が必要らしい...

面倒くさそうだったので、とりあえず、テクスチャシャドーの方を使ってみる。


// sceneMgr->setShadowTechnique(Ogre::SHADOWTYPE_STENCIL_ADDITIVE); sceneMgr->setShadowTechnique(Ogre::SHADOWTYPE_TEXTURE_MODULATIVE);

結果は、

Ninja3

お!なんか微妙に表示された。でもなんかちょっと汚い感じの影で、頭の部分の影は消えている。

カメラをもう少し引いてみる。


m_pCamera->setPosition(Vector3(100, 300, -300));

Ninja4

あぁ、影が消えた...

試しに、平行光源とスポットライトをコメントアウトして点光源だけにしてみる。


Ogre::Light* pointLight = sceneMgr->createLight("pointLight"); pointLight->setType(Ogre::Light::LT_POINT); pointLight->setPosition(Ogre::Vector3(0, 150, 250)); pointLight->setDiffuseColour(1.0, 0.0, 0.0); pointLight->setSpecularColour(1.0, 0.0, 0.0); /* Ogre::Light* directionalLight = sceneMgr->createLight("directionalLight"); directionalLight->setType(Ogre::Light::LT_DIRECTIONAL); directionalLight->setDiffuseColour(Ogre::ColourValue(.25, .25, 0)); directionalLight->setSpecularColour(Ogre::ColourValue(.25, .25, 0)); directionalLight->setDirection(Ogre::Vector3( 0, -1, 1 )); Ogre::Light* spotLight = sceneMgr->createLight("spotLight"); spotLight->setType(Ogre::Light::LT_SPOTLIGHT); spotLight->setDiffuseColour(0, 0, 1.0); spotLight->setSpecularColour(0, 0, 1.0); spotLight->setDirection(-1, -1, 0); spotLight->setPosition(Ogre::Vector3(300, 300, 0)); spotLight->setSpotlightRange(Ogre::Degree(35), Ogre::Degree(50)); */

Ninja5

前方に影ができた。

同じように今度は、平行光源だけにしてみると、

Ninja6

影はできない。

でも近づいてみるとできてる。

Ninja7

次に、スポットライトだけにしてみる。

Ninja8

これも影はできない。

近づいてみると、

Ninja9

できてる。

ん〜...原因はわからないけど、iPhoneで影を出したい場合は点光源だけにした方がよさげ。ステンシルバッファが使えれば他の光源を使ってカメラを引いた場合でも影ができるのだろうか?

とりあえず、今日はここまで。

最後に、照明を明るい環境光だけにして忍者の全身撮影。カシャッ

Ninja10

お疲れさまでした。

0 件のコメント:

コメントを投稿