大貓共和國

Meow

Python-Ogre Tutorial 3

請先閱讀「寫在OGRE Tutorial前面」,本文假設您的目錄配置都和我一樣。
本文參考PyOgre Beginner Tutorial 3

先建立C:\Python25\Python-Ogre-0.8\demos\tutorial\tut3.py,貼上這些程式碼:


# coding=big5

import Ogre as ogre
import SampleFramework

class TutorialApplication(SampleFramework.Application):
def createScene(self):

self.sceneManager.setWorldGeometry("terrain.cfg")
self.sceneManager.setSkyBox(True, "Examples/SpaceSkyBox")

def
chooseSceneManager(self):
self.sceneManager = self.root.createSceneManager(ogre.ST_EXTERIOR_CLOSE)
# 選擇場景管理器

if name == 'main':
ta = TutorialApplication()
ta.go()


wiki上使用getSceneManager,到Python-OGRE好像要用createSceneManger。這部份我不太確定,不過反正他work了:



有關SceneManager的細節我就不多談,有興趣的請自行查閱。我把焦點放在Terrian, Sky, Fog上。

地型
在一開始我們就copy了一些檔案到tutorial資料夾下,包括了terrian.cfg。其中指定了地型的材質、參數等等。最重要的是這一段:
# Heightmap source
PageSource=Heightmap
# Heightmap-source specific settings
Heightmap.image=terrain.png

terrian.png中,其實就是一個以顏色表示各點高度的heightmap。

天空

天空的貼圖法有三種:

  1. SkyBoxes,將天空貼在一個cube上
  2. SkyDomes,將天空貼在一個球體上 (但事實上他還是render在一個cube)
  3. SkyPlanes,將天空貼在平面上
Wiki上的推薦使用法:
  • 如果你會看到y軸為負的方向(例如從天空之城向下看),使用SkyBoxes
  • SkyDomes在接近y=0的地方會沒貼到圖,所以如果你的場景是被山或建築物圍繞著,推薦使用。
  • SkyPlane的優點是GPU cost極小,另外,其他兩種貼圖方式和fog並用時可能產生問題 (請詳閱wiki種fog一節)



再修改一下createScene…

def
createScene(self):
self.sceneManager.setWorldGeometry("terrain.cfg")

fadeColour = (0.9, 0.9, 0.9)
self.sceneManager.setFog(ogre.FOG_LINEAR, fadeColour, 0, 50, 515)
self.renderWindow.getViewport(0).backgroundColour = fadeColour

self.sceneManager.setSkyDome(True, "Examples/CloudySky", 5, 500)




被濃霧籠罩的山谷…




有關fog及plane的搭配請務必詳閱wiki,我在這就不多談了…

Python-Ogre Tutorial 2

請先閱讀「寫在OGRE Tutorial前面」,本文假設您的目錄配置都和我一樣。
本文參考PyOgre Beginner Tutorial 2

先建立C:\Python25\Python-Ogre-0.8\demos\tutorial\tut2.py,貼上這些程式碼:

# coding=big5

import Ogre as ogre
import SampleFramework

class TutorialApplication(SampleFramework.Application):

def createScene(self):
pass

def
createCamera(self):
self.camera = self.sceneManager.createCamera("PlayerCam")
# 建立PlayerCam (玩家攝影機物件)
self.camera.setPosition = (0, 10, 500)
# 設定位置
self.camera.lookAt((0, 0, 0))
# 設定方向
self.camera.nearClipDistance = 5
# 太近的東西看不到 (距離小於5)

def createViewports(self):
vp = self.renderWindow.addViewport(self.camera)
vp.backgroundColour = (0, 0, 0)
self.camera.aspectRatio = vp.actualWidth / vp.actualHeight

if name == 'main':
ta = TutorialApplication()
ta.go()

  • 這次我把註解直接打在程式碼裡面了,如果你的程式碼有中文的話,記得加上第一行coding的宣告,否則會沒辦法執行
  • 注意紅字的地方,position property沒辦法用,要用setPosition

經過了這段修改,我們得到一個….全黑的畫面?是的。

由於TutorialApplication是繼承SampleFramework.Application類別,就算我們不設定Camera及Viewport,上層的物件也會自動幫我們建立。現在我們只是Override上層的method,手動建立一次而已。

Camera簡單講就是玩家視角,Viewport這裡不用詳細解釋,有興趣深入了解請詳讀wiki吧。

光線與陰影 (Light&Shadow)

重頭戲來了….廢話不多說,我們來試試吧….修改
createScene函式:

def createScene(self):
sceneManager = self.sceneManager
sceneManager.ambientLight = (0, 0, 0)
# 不要ambient光源
sceneManager.shadowTechnique = ogre.SHADOWTYPE_STENCIL_ADDITIVE
# 設定陰影種類

ent = sceneManager.createEntity("Ninja", "ninja.mesh")
ent.castShadows = True # this is not actually needed
# 設定這個entity要有陰影效果
sceneManager.rootSceneNode.createChildSceneNode().attachObject(ent)
# 在scene中放置一個忍者

plane = ogre.Plane((0, 1, 0), 0)
# 建立地板平面
mm = ogre.MeshManager.getSingleton()
mm.createPlane('ground', ogre.ResourceGroupManager.DEFAULT_RESOURCE_GROUP_NAME,
plane, 1500, 1500, 20, 20, True, 1, 5, 5, (0, 0, 1))
# 建立地板平面的Mesh

ent = sceneManager.createEntity("GroundEntity", "ground")
sceneManager.rootSceneNode.createChildSceneNode().attachObject(ent)
ent.setMaterialName("Examples/Rockwall")
# 將地板明面貼上岩石材質
ent.castShadows = False

light = self.sceneManager.createLight("Light1")
light.type = ogre.Light.LT_POINT
# 建立一個點光源
light.setPosition(0, 150, 250)
# 設定光源位置

light.setDiffuseColour(1.0, 0.0, 0.0)
light.setSpecularColour(1.0, 0.0, 0.0)

注意紅色的部份,是與PyOgre API不相容的地方。先看看結果吧:



漆黑的忍者拖著長長的倒影 (驚)

注意我們把ambient光源設定為0了,在這裡我要稍微解釋一下。
一般3D圖學中的打光效果分為:
  • Ambient (我不太會翻譯…這個字是”周圍的”的意思)
    舉個例子,在一個漆黑的房間中,有一個門縫、窗縫透了一點光進來。這時整個房間都會近乎均勻的被打到一點點的光線。這個其實是經過很多反射、散射所造成的效果,但是真的去計算這些物理現像實在太難了,所以我們就假設所有物體都會被定量的光線照到。(就算不是realtime rendering,在photorealistic rendering也是有用ambient的)
  • Diffuse (散射)
  • Specular (鏡面反射)


現在我們將ambient設為零,而光源在忍者的背面,所以從正面看當然就是一片漆黑了。注意程式的最後兩行將光源設定圍紅色。

除了ambient外,Diffuse和Specular都是假定光線是從某種方向照過來的。OGRE裡光源有三種:
  1. Point:點光源
  2. Spotlight:聚光燈、手電筒,需要設定廣角範圍
  3. Directional:指向性光源,假設光源從無線遠處射來(如太陽)。需要設定範圍但不用設定位置。
先來個有三種光源的範例吧,在剛剛的
createScene後再加上:

light = sceneManager.createLight("Light3")
light.type = ogre.Light.LT_DIRECTIONAL
# 從無限遠處射來的光線
light.setDiffuseColour(.25, .25, 0)
light.setSpecularColour(.25, .25, 0)
# 設定顏色
light.setDirection(0, -1, 1)
# 要指定方向,不用指定位置

light = sceneManager.createLight("Light2")
light.type = ogre.Light.LT_SPOTLIGHT
# 聚光燈形式的光源
light.setDiffuseColour(0, 0, 1.0)
light.setSpecularColour(0, 0, 1.0)
# 顏色
light.setDirection(-1, -1, 0)
light.setPosition(300, 300, 0)
# 位置方向
light.setSpotlightRange(ogre.Degree(35), ogre.Degree(50))
# 廣角




看到三個方向的影子了,雖然這張圖看不出什麼差,但這是三種不同光源(藍字)造成的。照慣例,紅字是與wiki不同的地方。

另外,陰影模式也有三種:
  1. SHADOWTYPE_TEXTURE_MODULATIVE 最差,最少運算資源
  2. SHADOWTYPE_STENCIL_MODULATIVE
  3. SHADOWTYPE_STENCIL_ADDITIVE 最強,最多運算資源
有興趣深入了解的請看wiki

Python-Ogre Tutorial 1-2

上一篇..

座標系

OGRE的座標系系統是:x左右, y上下, z前後
有些其他系統會將y和z顛倒過來

再修改一下createScene:

def
createScene(self):
sceneManager = self.sceneManager
sceneManager.ambientLight = (1, 1, 1)

ent1 = sceneManager.createEntity("Robot", "robot.mesh")
node1 = sceneManager.rootSceneNode.createChildSceneNode("RobotNode")
node1.attachObject(ent1)

ent2 = sceneManager.createEntity("Robot2", "robot.mesh")
node2 = sceneManager.rootSceneNode.createChildSceneNode("RobotNode2", (50, 0, 0))
node2.attachObject(ent2)


放了兩台機器人:)
注意倒數第二行紅字的部份,第二台機器人有(50, 0, 0)的位移量。



def createScene(self):
sceneManager = self.sceneManager
sceneManager.ambientLight = (1, 1, 1)

ent1 = sceneManager.createEntity("Robot", "robot.mesh")
node1 = sceneManager.rootSceneNode.createChildSceneNode("RobotNode")
node1.attachObject(ent1)

ent2 = sceneManager.createEntity("Robot2", "robot.mesh")
node2 = node1.createChildSceneNode("RobotNode2", (0, 100, 0))
node2.attachObject(ent2)

再注意倒數第二行,我們這次不把第二台機器人接上SceneManager的root SceneNode,而接上第一台機器人的SceneNode,並且給了(0, 100, 0)的位移量 (正上方一百單位)。



注意:ent2的位置現在完全跟隨著ent1,要是第一台機器人移動,第二台也會跟著動。Wiki中提到可以拿來做grouping (像星海的航空母艦子機 XD)

來看看旋轉類的效果吧:


def
createScene(self):
sceneManager = self.sceneManager
sceneManager.ambientLight = (1, 1, 1)

ent1 = sceneManager.createEntity("Robot", "robot.mesh")
node1 = sceneManager.rootSceneNode.createChildSceneNode("RobotNode")
node1.attachObject(ent1)
node1.yaw(ogre.Degree(-90))

ent2 = sceneManager.createEntity("Robot2", "robot.mesh")
node2 = sceneManager.rootSceneNode.createChildSceneNode("RobotNode2", ogre.Vector3(50, 0, 0))
node2.attachObject(ent2)
node2.pitch(ogre.Degree(-90))

ent3 = sceneManager.createEntity("Robot3", "robot.mesh")
node3 = sceneManager.rootSceneNode.createChildSceneNode("RobotNode3", ogre.Vector3(100, 0, 0))
node3.attachObject(ent3)
node3.roll(ogre.Degree(-90))




注意紅色那三行就對了,不同的轉向函式。

最後,關於縮放(scaling)功能…

Wiki上的語法都不能用:
node.setScale(0.5, 0.2, 1)
node.scaleBy(2, 10, 1)


要用這個:
node.setScale(0.5, 0.2, 1)



這裡有一些PyOgre及Python-Ogre的差異,可是沒寫到scale,害我自己找半天 :(
http://python-ogre.python-hosting.com/wiki/FAQindex:見Converting from PyOgre




Tutorial 1的部份寫了最多,接下來的幾個Tutorial會寫必較少。不是我偷懶喔,而是點到為止就好了。尤其是OGRE Input處理的部份,最後做遊戲時是不太會用到的。

Python-Ogre Tutorial 1

請先閱讀「寫在OGRE Tutorial前面」,本文假設您的目錄配置都和我一樣。
本文參考PyOgre Beginner Tutorial 1

讓我們跟著上面那個tutorial的步驟一步一步做。首先我們看到這段程式,使用你熟悉的編輯器將他存到C:\Python25\Python-Ogre-0.8\demos\tutorial\tut1.py中

from pyogre import ogre
import SampleFramework

class TutorialApplication(SampleFramework.Application):
def createScene(self):
pass

if name == 'main':
ta = TutorialApplication()
ta.go()


執行看看
cd \Python25\Python-Ogre-0.8\demos\tutorial
python tut1.py

結果當然有error囉,因為他引用了PyOgre的package名稱而非Python-Ogre

將程式的前兩行改成

import Ogre as ogre
import SampleFramework




It works!!右下角有OGRE的mark,左下角有FPS的效能數據。整個畫面黑黑的一片,因為我們還沒有放任何東西在場景中。其實PyOgre和Python-OGRE最大的差別應該就是在這個import package name吧,其他程式碼幾乎都可以直接work。

接下來我就簡化地follow tutorial,還是推薦大家詳閱原版的tutorial喔!!

我們稍微改寫一下
createScene函式:

def _createScene(self):
sceneManager = self.sceneManager
sceneManager.ambientLight = ogre.ColourValue(1, 1, 1)

ent1 = sceneManager.createEntity("Robot", "robot.mesh")
node1 = sceneManager.rootSceneNode.createChildSceneNode("RobotNode")
node1.attachObject(ent1)


然後再執行看看…


可以按上下左右、移動滑鼠試試喔!

第一行取得了sceneManager物件,在OGRE的架構中,所有你看的見的東西都是被這個物件管理的。
第二行設定了光源,要是拿掉了這行,畫面就會變成一片漆黑了。ambientLight是一種光源的類型,等到光源那節我再詳細介紹。

第三到五行在畫面上放置了一個機器人,這部份比較複雜一些,我們需要了解一些物件:

  • MoveableObject:任何可以移動的物體。其實我們在這裡都不會直接取用他
  • Entity:MoveableObject的子類別,你可以將任何可以用3D Mesh表示的物件看成一個Entity。(例如:人、魚、鳥、車)
    然而燈光、攝影機…等等沒有3D模型的東西,他們是MoveableObject但不是Entity。
  • SceneNode:這個概念比較抽象…我真的不太會解釋,請務必看wiki原文。
    總而言之,每一個SceneNode都可以有他的parent及children,形成一個tree的結構。SceneNode記錄著相對於其parent的位置及方向。
    SceneManager中有個root SceneNode,一般來說他應該是一切其他SceneNode的根源。我是把他想成類似世界原點座標..


簡單來說,要在場景上放上一個物件至少要做三件事:
  1. 建立Entity
    程式碼第三行,載入robot的mesh並建立了這個entity
  2. 建立SceneNode
    程式碼第四行,注意他是從SceneManager建立這個SceneNode的。SceneNode必需以某種方式與SceneManager的root連結,我們才可以看的到他。
  3. 將Entity附在SceneNode上(程式碼第五行)


文章太長了,拆成兩篇…請看Python-Ogre Tutorial 1-2

寫在Python-OGRE Tutorial前面

接下來讓我們來看一些Tutorial吧。

從介紹OGRE的第一篇我就提到,學OGRE從Tutorial開始是最快的。在OGRE官方Wiki上有一系列的Tutorial教學

另外在PyOgre頁面中也有五個Tutorial,這五個Tutorial其實和上面的Basic Tutorial 1~5內容是一樣的,只是程式語言從C++變成了Python。

但是,目前並沒有為最新的Python-Ogre寫的Tutorial。事實上PyOgre及Python-Ogre的API根本就差不多,只有一些細微的差異。但如果你用PyOgre的程式直接貼到Python-Ogre,還是會出一點錯的。

接下來我會把這五個Tutorial的筆記整理出來,並且在Python-OGRE上執行。希望可以讓大家很快的上手Python-OGRE。

如果你的遊戲運算量、動作性沒有那麼高,那用Python開發應該不錯。但這五個Tutorial只是教你OGRE的基本操作,無論如何,C++版本的那整套Tutorial還是推薦大家一定要去去看一下的。




開始囉,讓我們先準備一下環境。我很偷懶的直接在c:\Python25\Python-Ogre-0.8\demos建一個tutorial的目錄,並且將所需的檔案copy過去,在命令提示字元下執行這些指令就可完成:

cd \Python25\Python-Ogre-0.8\demos
md tutorial
cd tutorial
copy ..\ogre\SampleFramework.py .
copy ..\ogre*.cfg .


SampleFramework.py是一個寫好的遊戲框架,定義了一些行為(例如說按上下左右攝影機就會移動,移動滑鼠就會轉向)。真正的implementation應該是在C:\Python25\Lib\site-packages\Ogre\sf.py,在前五個教學中我們先不用管他是什麼。

*.cfg是一些設定檔案,如果你完全照我的目錄配制的話,那就先不用管他是什麼東西了。

好,讓我們進入第一個Tutorial吧…

待續