Porting the NxOgre Tutorials

SiWi

19-08-2007 16:06:36

I like Cakebox very much but I think porting all the NxOgre tutorials could help. I would do this job. Only tell me if the PythonOgre team is working on the tutorials so we don´t double the work.
Second what version of NxOgre is wrapped for PythonOgre: 0.6 or 0.9.
Third: I think I will be very slow with wrapping them so don´t expect too fast results.
Fourth: I hope to find new bugs while wrapping. :D

SiWi

20-08-2007 13:59:08

Sorry for doubelpost, but just say me if I should start with the tutorials or not.
Also I plan to make one tutorial from all 1xxs. So there should be about 5-10 tutorials when I´m finished.

andy

20-08-2007 21:44:24

Oh yes please -- port the demos :)

Many Thanks !!!!!

Andy

SiWi

21-08-2007 09:23:25

It´s not a real tutorial, because I only took the cakebox demo and added some different objects. :P. But I think it perfectly replaces all the 10x Tutorials. So here it is:
10x-ish Tutorial:
# -*- coding: cp1252 -*-
"""

"""

import ogre.renderer.OGRE as ogre
import ogre.physics.PhysX as physx
import ogre.physics.NxOgre as nxogre
import CakeFramework as cf
import math
import random

class NxTutorial ( cf.Cake ):
def __init__ ( self ):
cf.Cake.__init__(self)

##////////////////////////////////////////////////////////////////////////////////////////////////

def start(self ):
self.World = nxogre.World("Log: html")

self.Scene = self.World.createScene("Main", self.SceneMgr,"gravity: yes, floor: yes")



self.Scene.createBody("cube.1m.mesh", nxogre.CubeShape(1,1,1), ogre.Vector3(0,3,0), "Mass: 100") #Cube
self.Scene.createBody("sphere.50cm.mesh", nxogre.SphereShape(0.5), ogre.Vector3(0,6,0), "Mass: 20") #Sphere
self.Scene.createBody("capsule.50cmx1m.mesh", nxogre.CapsuleShape(0.5,1), ogre.Vector3(0,8,0), "Mass: 15") #Capsule
self.Scene.createBody("convex1.mesh", nxogre.ConvexShape("convex1.mesh"), ogre.Vector3(0,10,0), "Mass: 7.5") #A mesh and a convex hull generated from the same model
self.Scene.createBody("prism.8x50cmx2m.mesh", nxogre.PrismShape(0.5,2,8), ogre.Vector3(0,12,0), "Mass: 5") #A Prism
self.Scene.createBody("cube.1m.mesh", nxogre.CubeShape(1,1,1), ogre.Vector3(0,3,5), "static: yes") #A static Cube
self.Scene.createBody("nx.convex2.mesh", nxogre.ConvexShape("nx.convex2.mesh"), nxogre.Pose(ogre.Vector3(5,5,5),ogre.Quaternion(math.sqrt(0.5),-math.sqrt(0.5),0,0)),
"Mass: 1000")
#A mesh and a convex hull generated from the same model and it has a Pose(don´t know what that is I took it from Betajaen)

for i in range(32):
h = random.randrange(1,4)
self.Scene.createBody("cube.1m.mesh", nxogre.CubeShape(1.0,h,1.0), ogre.Vector3(0,10.25 + h,i),"Mass: 100, node-scale: 1 " + str(h) + "1")
#32 random cubes

##////////////////////////////////////////////////////////////////////////////////////////////////
def stop(self):
## Time to go, better tell NxOgre we are leaving.
del self.World

##////////////////////////////////////////////////////////////////////////////////////////////////
#With this function torque is getting added to every body selected when dragging with the left mouse button pressed
def onFrame(self, _time) :
if not self.mTargetActor:
return
if self.InputHandler.isKeyDown(cf.Action.Z):
self.mTargetActor.addTorque(ogre.Vector3(0,0,150))
if self.InputHandler.isKeyDown(cf.Action.NEG_Z):
self.mTargetActor.addTorque(ogre.Vector3(0,0,-150))
if self.InputHandler.isKeyDown(cf.Action.X):
self.mTargetActor.addTorque(ogre.Vector3(150,0,0))
if self.InputHandler.isKeyDown(cf.Action.NEG_X):
self.mTargetActor.addTorque(ogre.Vector3(-150,0,0))
if self.InputHandler.isKeyDown(cf.Action.Y):
self.mTargetActor.addTorque(ogre.Vector3(0,150,0))
if self.InputHandler.isKeyDown(cf.Action.NEG_Y):
self.mTargetActor.addTorque(ogre.Vector3(0,-150,0))

def getWorld(self):
return self.World
##////////////////////////////////////////////////////////////////////////////////////////////////

def getTutorialSettings( self ):
self.TutorialName = "101"
self.TutorialDescription = "Cube on a plane"

##////////////////////////////////////////////////////////////////////////////////////////////////

if __name__ == '__main__':
import exceptions,sys
try:
application = NxTutorial ()
application.pre()
application.start()
application.WorldInstance = application.getWorld()
application.startRendering(application)
application.stop()
application.post()

except ogre.OgreException, e:
print e



P.S: Does anyone know what a Pose is? I´ll base all the tutorials on cakebox when possible. I think the next tutorials will be Character Controller and Terrain.

SiWi

24-08-2007 09:12:10

Tutorial Day: While I have problems with my CharacterController Tutorial, I´m glad to release my Terrain Tutorial.

WOW, Terrain is really tricky.
I used the ogre Terrain Demo and modified it for nxogre. Before you can do anything you have to copy all .dll files from demos/nxogre to demos/ogre.
The next step is that I used the nxogre cube and not the ogre cube. You can use the ogre cube, but I was too lazy. So if you want to use the nxogre cube add the following line in your demos/ogre/ressource.cfg file.

FileSystem=../media/SimpleMeshes

Now we can start coding. There are only a few lines getting added to the Terrain Demo(Demo_Terrain):
At the top of the file we add
import ogre.physics.PhysX as physx
import ogre.physics.NxOgre as nxogre

to be allowed to use nxogre.
Add the end of the function createScene we add:
self.world = nxogre.World()
self.Scene = self.world.createScene("Main",self.sceneManager,"gravity: yes, floor: yes")

You always need these lines before you can do anything with nxogre.
self.Actor = self.Scene.createActor("terrain",nxogre.TerrainShape("terrain.png", 100, "mesh-scale: 2.923976 1 2.923976"),ogre.Vector3(0,1,0),"static: yes")

This line is the whole trick and I had many problems with it. Here we create Actor. That means it is an only phyiscally object you can´t see.
First parameter is it´s name, second parameter is the shape or collision model. Of course we want to create a TerrainShape. Listen up NOW! Thats the real trick. First parameter passed is the heightmap picture. It has to be loaded with Ogre before. The second parameter passed is maxheight of the terrain. We get it from Terrain.cfg:
MaxHeight=100
PageWorldX=1500
PageWorldZ=1500

This are the three important lines you can find in your cfg.
The next argument we pass to TerrainShape is "mesh-scale: 2.923976 1 2.923976". This is a param. NxOgre makes losts of use of Params. There are two differnet ways to pass params. You see the first way above, via a string. If you want to pass more params you have to put them in the same string. Don´t make multiple strings. The second way would be something like this:

sp = nxogre.ShapeParams()
sp.setToDefault()
sp.meshScale = ogre.Vector3(2.9239766,1,2.9239766)
nxogre.TerrainShape("terrain.png", 100, sp)

Now lets get back to the tricks: With the Param we scale the terrain. You get the X and Z scale from PageWorldX/XSizeofheightmap and PageWorldZ/YSizeofheightmap. In our case it is 1500/513 and 1500/513.
Now we have finished the TerrainShape and we have two arguments passed to the Actor left. OgreVector(0,1,0). Position of the Terrain. I don´t why, but you need this position that nxogre and ogre Terrain fit together.
The last argument is a param and with this param we define that the Terrain is static, so it doesn´t move.
I add two last lines to the code in order to create a few boxes:

for i in range (10):
self.Scene.createBody("cube.1m.mesh", nxogre.CubeShape(10,10,10), ogre.Vector3(750,2500+i,528), "mass: 10, node-scale: 10 10 10")

Thats it.
I want to thank Betajaen and TMT for the help with this Tutorial.

Last, but not least the complete code:

# This code is in the Public Domain
# -----------------------------------------------------------------------------
# This source file is part of Python-Ogre
# For the latest info, see http://python-ogre.org/
#
# It is likely based on original code from OGRE and/or PyOgre
# For the latest info, see http://www.ogre3d.org/
#
# You may use this sample code for anything you like, it is not covered by the
# LGPL.
# -----------------------------------------------------------------------------
import ogre.renderer.OGRE as ogre
import SampleFramework as sf
import ogre.physics.PhysX as physx
import ogre.physics.NxOgre as nxogre

class TerrainApplication(sf.Application):
def _chooseSceneManager(self):
# self.sceneManager = self.root.createSceneManager("TerrainSceneManager")
self.sceneManager = self.root.createSceneManager(ogre.ST_GENERIC)
self.sceneManager = self.root.createSceneManager(ogre.ST_EXTERIOR_CLOSE)

def _createCamera(self):
self.camera = self.sceneManager.createCamera('PlayerCam')
self.camera.setPosition (ogre.Vector3(128, 25, 128))
self.camera.setPosition (128, 25, 128)
self.camera.position = ogre.Vector3(128, 25, 128)
self.camera.position = (128, 25, 128)
self.camera.position = [128, 25, 128]
self.camera.position = 128, 25, 128

self.camera.lookAt(0, 0, -300)
self.camera.NearClipDistance = 1

# infinte far clip plane?
#if self.root.renderSystem.capabilities.hasCapability(ogre.RSC_INFINITE_FAR_PLANE):
#self.camera.farClipDistance = 0
#else:
self.camera.FarClipDistance = 1000

def _createScene(self):
sceneManager = self.sceneManager
camera = self.camera

sceneManager.AmbientLight = 0.5, 0.5, 0.5

# Create a light
l = sceneManager.createLight("MainLight")
# Accept default settings: point light, white diffuse, just set position
# NB I could attach the light to a SceneNode if I wanted it to move automatically with
# other objects, but I don't
l.setPosition(20,80,50)

# Fog
# NB it's VERY important to set this before calling setWorldGeometry
# because the vertex program picked will be different
fadeColour = (0.93, 0.86, 0.76)
sceneManager.setFog(ogre.FOG_LINEAR, fadeColour, 0.001, 500.0, 1000.0)
self.renderWindow.getViewport(0).BackgroundColour = fadeColour

sceneManager.setWorldGeometry('terrain.cfg')

if (self.root.getRenderSystem().getCapabilities().hasCapability(ogre.RSC_INFINITE_FAR_PLANE)):
camera.setFarClipDistance(0)

# setup the sky plane
plane = ogre.Plane()
# 5000 world units from the camera
plane.d = 5000
# Above the camera, facing down
plane.normal = -ogre.Vector3.UNIT_Y

## Setup a nice starting position for the camera
camera.setPosition(707,2500,528)
camera.setOrientation(ogre.Quaternion(-0.3486, 0.0122, 0.9365, 0.0329))
camera.orientation = ogre.Quaternion(-0.3486, 0.0122, 0.9365, 0.0329)
camera.orientation = -0.3486, 0.0122, 0.9365, 0.0329

self.world = nxogre.World()
self.Scene = self.world.createScene("Main",self.sceneManager,"gravity: yes, floor: yes")
self.Actor = self.Scene.createActor("terrain",nxogre.TerrainShape("terrain.png", 100, "mesh-scale: 2.923976 1 2.923976"),ogre.Vector3(0,1,0),"static: yes")
#There is a second way to create the shape:
#sp = nxogre.ShapeParams()
#sp.setToDefault()
#sp.meshScale = ogre.Vector3(2.9239766,1,2.9239766)
#nxogre.TerrainShape("terrain.png", 100, sp)
for i in range (10):
self.Scene.createBody("cube.1m.mesh", nxogre.CubeShape(10,10,10), ogre.Vector3(750,2500+i,528), "mass: 10, node-scale: 10 10 10")
#for i in range (10):
#self.Scene.createBody("ogrehead.mesh", nxogre.CubeShape(1.0,1.0,1.0), ogre.Vector3(750,2500+i,528), "mass: 10")
#self.Scene.createBody("cube.1m.mesh", nxogre.CubeShape(1.0,1.0,1.0), ogre.Vector3(707,3000,528), "mass: 10")

def _createFrameListener(self):
self.frameListener = TerrainListener(self.renderWindow, self.camera, self.sceneManager)
self.root.addFrameListener(self.frameListener)

class TerrainListener(sf.FrameListener):
def __init__(self, renderWindow, camera, sceneManager):
sf.FrameListener.__init__(self, renderWindow, camera)
self.sceneManager = sceneManager
self.moveSpeed = 50.0
self.raySceneQuery = sceneManager.createRayQuery(ogre.Ray(camera.getPosition(),
ogre.Vector3.NEGATIVE_UNIT_Y))
self.camera = camera
#self.camera.setPosition (self.camera.getPosition() + ogre.Vector3(0.0, 10.0, 0.0))

def frameStarted(self, frameEvent):
# clamp to terrain
updateRay = ogre.Ray()
updateRay.setOrigin (self.camera.getPosition() + ogre.Vector3(0.0, 10.0, 0.0))
updateRay.setDirection (ogre.Vector3.NEGATIVE_UNIT_Y)
self.raySceneQuery.Ray = updateRay
for queryResult in self.raySceneQuery.execute():
if queryResult.worldFragment is not None:
pos = self.camera.getPosition()
self.camera.setPosition (pos.x, pos.y - queryResult.distance + 15.0, pos.z)
break

return sf.FrameListener.frameStarted(self, frameEvent)

if __name__ == '__main__':
try:
application = TerrainApplication()
application.go()
except ogre.OgreException, e:
print e

witmud

29-08-2007 02:46:19

That is great. SiWi, Thank you.

I plan to move to PhysX from ODE. But I don't know what is Python-PhysX's status, is stable?

Anyway, I am very glad to see your great work.

SiWi

29-08-2007 08:54:47

It is stable. Thank you for your feedback. More Tutorials are coming. :D
If you plan to move to PhysX, you have to note the license. You may use ODE in commercial projects for free, but you have to pay for PhysX.
Anyway you are allowed to use PhysX in noncommercial projects.
If you want to use it in noncommercial projects I would change to PhysX, because it´s s much easier and has a lot more features.

andy

29-08-2007 15:48:53

I also agree on focusing on NxOgre as at the moment it is the most active Physics project for Ogre -- both OgreOde and OgreNewt are less active -although to be fair perhaps this is because they both work well : )

There has been a new release of NxOgre and I'll build a Python-Ogre binary release for it soon..

Cheers

andy

reptor

01-09-2007 23:08:26

If you plan to move to PhysX, you have to note the license. You may use ODE in commercial projects for free, but you have to pay for PhysX.
Anyway you are allowed to use PhysX in noncommercial projects.
If you want to use it in noncommercial projects I would change to PhysX, because it´s s much easier and has a lot more features.


Since PhysX release 2.6 you are allowed to use PhysX also in commercial products without paying Ageia.

witmud

02-09-2007 09:58:53

When I know Novodex in 2005, you need to pay a lot. But, Novodex(PhysX) is free after end of 2006, I just know it in a month. You can check the new license for developers on Ageia's website. That is the why I move. I don't know why to use others,such as Havok,Newton,ODE,Bullet.

SiWi

03-01-2008 13:38:22

It´s an old topic, but... . I started playing around with Nxogre again and so here is an new Tutorial.
This Character tutorial is based on Cake.
We start with basic cake staff:
import ogre.renderer.OGRE as ogre
import ogre.physics.PhysX as physx
import ogre.physics.NxOgre as nxogre
import CakeFramework as cf

class NxTutorial ( cf.Cake ):
def __init__ ( self ):
cf.Cake.__init__(self)

##////////////////////////////////////////////////////////////////////////////////////////////////

def start(self ):
self.World = nxogre.World("Log: html")

self.Scene = self.World.createScene("Main", self.SceneMgr,"gravity: yes, floor: yes")


Now we create an 'FakeFloor'. It seems like characters like to fall through the standard floor(*happy about new character system in nxogre bleeding*), so we need an Actor that acts as our new floor.
self.Scene.createActor('FakeFloor',nxogre.CubeShape(100,2.1,100),ogre.Vector3(0,-0.05,0),'static:yes')

Let´s create our Character:
self.Character=self.Scene.createCharacter('Char',
ogre.Vector3(0,4,0), "type: box, dimensions: 1 2 1" )

The Parameters:
1.It needs an unique Name
2.It needs an position
3.The nxogre Params. For type you can define box or capsule,the dimensions are the size in metres.

We want to see it, so it needs a entity:
self.Character.attachMesh('Cube.1m.mesh')

That´s the main part.
Now we only have to change the FrameListener:
def onFrame(self, _time) :
if self.InputHandler.isKeyDown(cf.Action.Z):
self.Character.addMovement(nxogre.Character.DR_StepLeft)
if self.InputHandler.isKeyDown(cf.Action.NEG_Z):
self.Character.addMovement(nxogre.Character.DR_StepRight)
if self.InputHandler.isKeyDown(cf.Action.X):
self.Character.addMovement(nxogre.Character.DR_Forward)
if self.InputHandler.isKeyDown(cf.Action.NEG_X):
self.Character.addMovement(nxogre.Character.DR_Backward)


Note that you don´t need to use any Physic to move the character. But that´s what chracters are there for.