Crash when using queryResult.worldFragment

srekel2

11-10-2005 20:25:11

Here's a part of the function we use to determine which "actor" the player currently has under his mouse:



def shootRay(self):
x, y = self.mousePointerOverlay.xScroll, self.mousePointerOverlay.yScroll
x, y = (x + 1) / 2, 1 - (y + 1) / 2
#print x,y
mouseRay = self.camera.getCameraToViewportRay(x, y)
self.raySceneQuery.ray = mouseRay
for queryResult in self.raySceneQuery.execute():
### Check if we hit the world
### This is sadly not implemented in pyogre yet
if queryResult.worldFragment is not None:
#print "world",type(queryResult.worldFragment),queryResult.worldFragment.singleIntersection
#for x in dir(queryResult.worldFragment): print x
if self.selectedActor is not None:
#self.selectedActor.entityNode.scale = ogre.Vector3(self.selectedActor.meshScale)
self.selectedActor.entityNode.showBoundingBox = False
self.selectedActor = None
print queryResult.worldFragment ###### CRASH!!
break
else:
### We have hit a movable. We filter away some of the stuff that aren't interesting
### CHANGED: We just check if it is smoething we are interested in
#if "tile" not in queryResult.movable.name and \
# "Water" not in queryResult.movable.name and \
# "PS" not in queryResult.movable.name and \
# "Order" not in queryResult.movable.name and \
# "Laser" not in queryResult.movable.name and \
# "gun" not in queryResult.movable.name:
if "entity" in queryResult.movable.name:
if "Turret" in queryResult.movable.name and "gun" not in queryResult.movable.name and \
"PS" not in queryResult.movable.name or \
"Wall" in queryResult.movable.name or \
"Zeppelin" in queryResult.movable.name or \
"Building" in queryResult.movable.name:
#print queryResult.movable.name
### Find which actor we hit
index = int(queryResult.movable.name.split("_")[-1])# - 1
### Check if the currently selected actor is NOT the one that is below
### the mouse pointer; only then do we want to do something
### We also check if the actor under the mouse pointer is dying, because
### then we obviously do not want to do anything.
if self.selectedActor is not self.dataManager.actors[index] and \
self.dataManager.actors[index].state != DYING:
### If we got here, that means we have a valid actor under the mouse pointer
### Check if the currently selected actor is something
if self.selectedActor is not None:
### If so, reset its scale
#self.selectedActor.entityNode.scale = ogre.Vector3(self.selectedActor.meshScale)
### CHANGED TO
self.selectedActor.entityNode.showBoundingBox = False
### Set the currently selected actor to be the actor under the mouse pointer
self.selectedActor = self.dataManager.actors[index]
### Enlargen the actor
###CHANGED
#self.selectedActor.entityNode.scale *=1.2 # = ogre.Vector3(self.selectedActor.meshScale)
self.selectedActor.entityNode.showBoundingBox = True
break



Basically, it looks through the results and filters them. If the closest one is interesting, it "selects" it (makes its bounding box visible). You don't really have to read anything after the #####CRASH line.

There is a problem, however. We use the basic Terrain Scene Manager, and it works fine for most things, however, when the terrain isn't "between" the skybox and the mouse pointer, it doesn't really work. So I added a "print queryResult.worldFragment", but that makes the game crash, even though I check "if queryResult.worldFragment is not None:" before.

Clay

11-10-2005 21:10:09

I've opened up a bug for this: https://developer.berlios.de/bugs/?func=detailbug&bug_id=5333&group_id=3464

Could you do me a quick favor?

Run the program with the following lines replacing "print queryResult.worldFragment ###### CRASH!!" and paste the results here (or let me know they crashed). Run them individually (don't put them one after another, try one, get results, try another, get results).

print type(queryResult) #1
print dir(queryResult) #2
print `queryResult` #3
print type(queryResult.worldFragment) #4
print dir(queryResult.worldFragment) #5
print `queryResult.worldFragment` #6


Thanks!

srekel2

11-10-2005 21:35:48

Absolutely. I'll get right on it (post/edit in 5-10 minutes)

EDIT: Sorry if I kept you waiting, some things came inbetween. Anyways, here are the results. Sadly, I didn't think to check if there was a difference between looking at the terrain and looking out at the skybox until the fourth test. It seemed (and it should be so) that it didn't reach the print line when I aimed directly at the skybox. Do you want me to test that again?


print type(queryResult) #1
<class 'pyogre.ogre.RaySceneQueryResultEntry'>


print dir(queryResult) #2
['__class__', '__del__', '__delattr__', '__dict__', '__doc__', '__getattribute__', '__hash__', '__init__', '__lt__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__str__', '__weakref__', 'distance', 'movable', 'this', 'thisown', 'worldFragment']



print `queryResult` #3
<pyogre.ogre.RaySceneQueryResultEntry; proxy of C++ Ogre::RaySceneQueryResultEntry instance at _40aba118_p_Ogre__RaySceneQueryResultEntry>
<pyogre.ogre.RaySceneQueryResultEntry; proxy of C++ Ogre::RaySceneQueryResultEntry instance at _08a6a118_p_Ogre__RaySceneQueryResultEntry>
<pyogre.ogre.RaySceneQueryResultEntry; proxy of C++ Ogre::RaySceneQueryResultEntry instance at _0040a018_p_Ogre__RaySceneQueryResultEntry>


print type(queryResult.worldFragment) #4
<type 'PySwigObject'>
(only on terrain)


print dir(queryResult.worldFragment) #5
[]

print `queryResult.worldFragment` #6
<Swig Object at _5c8b7e0b_p_Ogre__SceneQuery__WorldFragment>

Clay

11-10-2005 22:13:38

print type(queryResult.worldFragment) #4
<type 'PySwigObject'>
(only on terrain)


print dir(queryResult.worldFragment) #5
[]

print `queryResult.worldFragment` #6
<Swig Object at _5c8b7e0b_p_Ogre__SceneQuery__WorldFragment>

Ahhh this is the problem right there. Thanks, I'll get on it.

srekel2

11-10-2005 22:33:22

No problem. :)

A fix for this would be quite valuable to us, as it seems our missiles aren't doing quite what they should, and I think this is the reason for it.

Clay

11-10-2005 22:46:46

Does the movable object list work on this? It's just the worldFragment that doesn't work right?

srekel2

11-10-2005 22:53:52

Yup, shooting rays at movables work fine, except, it seems, when there isn't any terrain behind the movable.

I can't prove it, but everything seems to point to that. Do you want a more elaborate description of what I've seen?

srekel2

11-10-2005 23:11:39

Oh, and in case I wasn't clear; shooting rays at the terrain works too, if you just want the distance.

So, you can do this:



def updateHeight(self):
### Create a ray that starts below the actors position, under the ground
self.ray.origin = ogre.Vector3(self.position[X], 0, self.position[Z])
self.ray.direction = ogre.Vector3.UNIT_Y
self.raySceneQuery.ray = self.ray
### Query the ray. If terrain is hit, update height of actor
for queryResult in self.raySceneQuery.execute():
if queryResult.worldFragment is not None: # or "Wall" in queryResult.movable.name:

self.ogreNode.translate (0,
queryResult.distance - self.position[Y] + self.heightAdjust,
0)
self.position = ( self.position[X],
queryResult.distance + self.heightAdjust,
self.position[Z])

break



That code makes sure that an actor is always on the terrain, plus the "self.heightAdjust" value which we've hard coded for different meshes.

Clay

12-10-2005 00:30:46

This is a pretty simple problem with a complex solution. SWIG cannot handle nested classes/structures. I tried fixing this but the aproach I was taking didn't work out. I'll give it another shot in a few days. I have another midterm to study for.

srekel2

12-10-2005 12:20:54

Ok.

It seems weird to me; almost as if it was a bug in ogre or something, but I really doubt that. When the ray misses the terrain, it misses everything. That is,

self.raySceneQuery.execute() = []

when the ray doesn't find any terrain, even if there is a movable in the way. Otherwise it seems to work fine. I don't know much about SWIG, but to me it seems like this problem doesn't only have to do with worldFragment, but also in the parsing of the results from OGRE?

I mean, OGRE should still return a list of results with movables, right? I hope you understand what I mean. :) But as I said, I'm not familiar with SWIG and you probably understand the problem better than I do.

Clay

12-10-2005 16:16:05

It does sound like a problem with ogre. I may spend some time and write up a C++ test to see it happening. I am almost certain that (as of version 1.0.0) it worked properly. I was fiddling with that code myself, but I'll have a look. Thanks.

Edit: Also note that the terrain chunks itself are returned as movable objects. Are you sure that it when it returns when you click on terrian that the movable objects are the movable objects you think they are?

srekel2

12-10-2005 17:14:45

Yup, I know they are returned as movables with the name "tile_<something>". And we always filter them in the code by doing this:


(...)
if "tile" not in queryResult.movable.name:
# we've hit something we're interested in
do_something()



That seems to work great. We're using quite a lot of rays in our game, and the problems have only started to show recently, because we've added enemy "zeppelins"/blimps and missiles. The missiles target the zeppelins, and shoot rays in front of it. If the distance is smaller than some value, the missile hit and the zeppelin should die.

However, this doesn't always work that well, and we didn't understand the reason until we noticed that you couldn't always target the zeppelin with the mouse either. We never had problems (at least none that we noticed) with other objects/actors because they always had terrain behind them.

Clay

14-10-2005 06:03:53

Ok, worldFragment is now partially bound. Swig refuses to wrap the class because it does not support nested subclasses. I dug into the python/c api to make this work. Basically it boils down to this:
  1. The geometry variable has been removed. void pointers are bad.[/*:m]
  2. I'm not 100% sure that the planes list is properly wrapped. I did not have code to test it with. It works fine if there is no list though.[/*:m]
  3. You cannot use dir(worldFragment). I'm not sure what I was supposed to do differently, but I may come back and fix this later.[/*:m][/list:u]

    These should work now:
    print queryResult.worldFragment.singleIntersection
    print queryResult.worldFragment.fragmentType
    print queryResult.worldFragment.planes
    print queryResult.worldFragment.renderOp


    I have not looked over the ray not targeting movable objects that do not have terrain behind them. The C++ code looks to be in order, but I'll have to write some test code later to try it out.

srekel2

16-10-2005 22:36:31

There seems to be a problem with the new scene query. It may be because I don't know how to set it up, but the results are this:

updateHeight() shoots a ray from an actors position but at y = 0 straight up (as you can see above), and sets the actors height as the resulting distance. This has worked fine, but now, they seem to go below the ground in a random manner. I could try and give you a better explanation if you want, but this might help more:


print queryResult.worldFragment.singleIntersection
print queryResult.worldFragment.fragmentType
print queryResult.worldFragment.planes
print queryResult.worldFragment.renderOp


outputted.. damn, I lost it. Anyways, it was something like this:

Vector3(363656467647474764767476322222.00000, 0, 463566738975650225062.000000) (very big numbers)
6
None
None

I tried going back to revision 187 (the previous one) for OgreSceneQuery.i and that fixed the problem. Like I said, I'm not sure how I was supposed to use it, so I tried this:


try:
self.raySceneQuery.worldFragmentType = 6
except:
print "DM: nonononononononononononono"

and
self.raySceneQuery.worldFragmentType = "singleIntersection"
but both got caught by the error handling.

Clay

16-10-2005 23:02:46

I modified the TerrainDemo to try do what you are doing (shooting a vector upwards instead of dowards) and it works fine for me. Here's the test I ran:
# This code is in the public domain
import pyogre.ogre as ogre
import SampleFramework as sf

class TerrainApplication(sf.Application):
def _chooseSceneManager(self):
self.sceneManager = self.root.getSceneManager(ogre.ST_EXTERIOR_CLOSE)

def _createCamera(self):
self.camera = self.sceneManager.createCamera('PlayerCam')
self.camera.position = (128, 100, 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)

fadeColour = ogre.ColourValue(0.93, 0.86, 0.76)
sceneManager.setFog(ogre.FOG_LINEAR, fadeColour, 0, 500.0, 1000.0)
self.renderWindow.getViewport(0).backgroundColour = fadeColour

sceneManager.setWorldGeometry('terrain.cfg')

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.position,
ogre.Vector3.NEGATIVE_UNIT_Y))
self.camera = camera
self.camera.position = self.camera.position + ogre.Vector3(0.0, 10.0, 0.0)

def frameStarted(self, frameEvent):
# clamp to terrain
updateRay = ogre.Ray()
updateRay.origin = self.camera.position * ogre.Vector3(1.0, 0.0, 1.0)
print "\norigin:", updateRay.origin
updateRay.direction = ogre.Vector3.UNIT_Y
self.raySceneQuery.ray = updateRay
for queryResult in self.raySceneQuery.execute():
if queryResult.worldFragment is not None:
pos = self.camera.position
self.camera.position = (pos.x, queryResult.distance + 15.0, pos.z)
print "dist:", queryResult.distance
print "sI:", queryResult.worldFragment.singleIntersection
break

return sf.FrameListener.frameStarted(self, frameEvent)

if __name__ == '__main__':
application = TerrainApplication()
application.go()


As you can see from the output, the intersection works and there doesn't seem to be any problems. Are you sure you are shooting the ray from the correct position AT the terrain? Could you modify the above code so I can see the problem?

Also you cannot change any portion of the worldFragment. It's basically a read only object. Sorry this seems like a big kluge, it more or less is. Until SWIG starts understanding nested classes I have to do all of this by hand.

srekel2

16-10-2005 23:14:35

That does look like what we're doing. I can't try it now because I'm trying to figure out another mystery (non-pyogre related I think) right now. I'll see if I get the time tomorrow.

srekel2

18-10-2005 23:38:19

Well, I think I know what the problem is. Your example worked fine, whilst mine gave the same wierd results. So I put this

print queryResult.worldFragment.singleIntersection
print queryResult.worldFragment.fragmentType
print queryResult.worldFragment.planes
print queryResult.worldFragment.renderOp
print ""


in your example, and I saw one difference: your rays hit something with queryResult.worldFragment.fragmentType == 2 and mine are 6.

So I removed the break, making your code look like this:



for queryResult in self.raySceneQuery.execute():
#print 4
if queryResult.worldFragment is not None:
#print 5
print queryResult.worldFragment.singleIntersection
print queryResult.worldFragment.fragmentType
print queryResult.worldFragment.planes
print queryResult.worldFragment.renderOp
print ""

pos = self.camera.position
#print pos
self.camera.position = (pos.x, queryResult.distance + 15, pos.z)




This resulted in a bunch of lines looking like these:


> Executing: C:\Program Files\ConTEXT\ConExec.exe "C:\Python24\python.exe" "RayTest.py"

(...)

Vector3(128.000000, 58.255692, 128.000000)
2
None
None

Vector3(-0.000000, 0.000000, 0.000000)
6
None
None

Vector3(128.000000, 58.255692, 128.000000)
2
None
None

Vector3(69991461078022444000000000000000000.000000, 0.000000, 0.000000)
6
None
None

Vector3(128.000000, 58.255692, 128.000000)
2
None
None

Vector3(69991461078022444000000000000000000.000000, 0.000000, 0.000000)
6
None
None



So, for some reason, your rays stop at one type of world fragment, and mine stop at another. I'm not sure why, because both use sortbydistance. Anyways, it was easily fixed (hacked) by adding a check to see if the queryResult.worldFragment.fragmentType indeed is 2.


EDIT: Oh. I just realized that your code doesn't sort by distance. I did the same thing with mine, and voila! It would feel a lot safer to sort by distance though, I mean, it sounds like some strange results may occur otherwise.

Strange though. The API states this for the world fragment type:



Enumeration values:
WFT_NONE Return no world geometry hits at all.
WFT_PLANE_BOUNDED_REGION Return pointers to convex plane-bounded regions.
WFT_SINGLE_INTERSECTION Return a single intersection point (typically RaySceneQuery only).
WFT_CUSTOM_GEOMETRY Custom geometry as defined by the SceneManager.
WFT_RENDER_OPERATION General RenderOperation structure.


Only five values. So what's number 6 mean? :)

Clay

19-10-2005 09:08:43

Very strange, also those are only 0-4, no 5 or 6. I'll post this in the Ogre forums to see if anyone knows what that is. In any case, I guess your problem is solved then? You can just make sure it's 2 then use those vectors.

I just committed a cleaner version of worldFragment code.

Can you still not target things that are in the air? Let me know if there are any more outstanding issues with this. I'm losing track.

If there is anything else can you open a bug for me? Otherwise I'm afraid it's going to get lost.

srekel2

22-10-2005 23:53:42

Hmm, I just realized that the problem which meant I couldn't target things in the air might have been my fault, but I'm not sure yet.

Anyway, I checked out the latest PyOgre and now it seems you can't do this:


print "mov", queryResult.movable.name


if the movable is a particle system. It crashes... I opened a bug for it (https://developer.berlios.de/bugs/?func ... up_id=3464), I hope I did it the right way. I didn't know what group to put it in so I put it in group None :oops:, and I didn't set the priority so I guess it got set to 5 by default.

Clay

23-10-2005 01:53:18

Ah ok thanks. I'll get to work on it. It doesn't matter if everything's not perfect on the bug, but if it's not on the list I forget it.

srekel2

23-10-2005 10:53:06

Thanks (again :)). Obviously, the crash bug is more important for us.

I posted about ray queries in the main forum, because, while there was an error in our ray-querying-from-camera-code, there is still some bug in OGRE (given how it behaves, it seems wierd that it should be PyOgre's fault).

It's here: http://www.ogre3d.org/phpBB2/viewtopic.php?t=14638

Clay

23-10-2005 17:31:59

I think you are one of those people who have a gift for finding those hard to reach bugs. =)

Unfortunently I have a major project due tuesday. I'll take a look over these on thursday. I've already started on them, but the problem seems non-trivial. Thanks for the bug reports.

srekel2

23-10-2005 17:48:54

Haha, ok :)

Well, until then I guess we can do some ugly hack and just check the type of the movable before we do something with it. :)

Clay

23-10-2005 23:51:44

Ok this is fixed as of revision 253.

srekel2

24-10-2005 08:00:53

Kick ass! :)