Found another "bug"

What it says on the tin: a place to discuss proposed new features.
Post Reply
User avatar
zeroskill
Greenskin
Posts: 123
Joined: Wed Jul 20, 2005 8:30 pm
Contact:

Found another "bug"

Post by zeroskill »

Firstly, this is arguable as to whether or not this is a bug. Here is the problem:

Create an entity and give it a UserDefinedObject pointer.
Now add that entity to a StaticGeometry object.
Destroy your original entity (don't need it anymore).
During scene queries, the static geometry region appears as a movable object, complete with a UserDefinedObject pointer, however that pointer was never preserved and is now set to NULL.

This pointer is lost because StaticGeometry breaks all entities down to their submeshes, and does not build StaticGeometry::Regions from them until the StaticGeometry::build() function is called. StaticGeometry, by itself, is not a MoveableObject, and thus has no place to add a UserDefinedObject. It would be useful to have the ability to attach user data to StaticGeometry, as knowing what you're hitting during a scene query is arguably just as important as knowing if you hit at all.

Given the complex nature of StaticGeometry (its contents can be subdivided into multiple regions if necessary) it would probably be best to not consider this an actual bug, and instead look at it as a necessary feature addition. Instead of attempting to maintain the UserDefinedObject pointer for each entity that is added to a StaticGeometry object, instead it would probably make more sense to allow users to attach a UserDefinedObject pointer to a StaticGeometry object as a whole. If you want separate UserDefinedObject pointers, make separate StaticGeometry. The usefulness vs. speed tradeoff of that solution seems fairly balanced to me.
genva
OGRE Retired Team Member
OGRE Retired Team Member
Posts: 1603
Joined: Wed Oct 20, 2004 7:54 am
Location: Beijing, China
x 1

Post by genva »

Already exists API to do that: iterate over the regions via StaticGeometry::getRegionIterator and attach UserDefinedObject to StaticGeometry::Region. Of course, there are no ways to gather UserDefinedObject from entities and store them to StaticGeometry automatically, you should do that yourself.
User avatar
zeroskill
Greenskin
Posts: 123
Joined: Wed Jul 20, 2005 8:30 pm
Contact:

Post by zeroskill »

Hm, very interesting. You are, as usual, correct that the API does currently expose the ability to attach a UserDefinedObject to a StaticGeometry::Region through the use of getRegionIterator(). That was an oversight on my part. What I don't understand is how this type of access can allow the programmer to logically attach a meaningful UserDefinedObject to any one specific region.

By adding entities to a StaticGeometry object, you are adding their submeshes to a disorganized list. That list is then used to build meaningful regions that can be used for more efficient rendering. So clearly once you add an entity to a StaticGeometry, you lose all knowledge of where it just went. There is no way to be certain which region(s) the data from the entity occupies, or in other words: you have no idea what data each region actually represents.

Because of this, the ability to assign per-region UserDefinedObjects seems rather pointless from an application's point of view. The only logical thing to do is attach the same UserDefinedObject to all regions of a StaticGeometry, and use a different StaticGeometry object for each different entity (or entity type depending on your needs). By doing this, you can at least be sure that, given any StaticGeometry::Region from a ray query, you'll be able to find out what object you're actually hitting.

To sum it all up, I have yet to see the advantage of per region UserDefinedObjects. At the very least, perhaps there should be a few member functions implemented at the StaticGeometry level that would allow the user to assign UserDefinedObjects and Query flags to a StaticGeometry object as a whole, and thus part of the build process would allow the StaticGeometry object to prefill each region with this known user provided data.
User avatar
sinbad
OGRE Retired Team Member
OGRE Retired Team Member
Posts: 19269
Joined: Sun Oct 06, 2002 11:19 pm
Location: Guernsey, Channel Islands
x 66
Contact:

Post by sinbad »

This is the nature of StaticGeometry - it batches things up making individuals part of a larger whole. Therefore the response to the argument that it loses the identity of the Entity when it goes in is "well, sure, what else did you expect?".

Items added to StaticGeometry are no longer individuals. They are part of a much bigger whole and therefore should not be expected to keep their identity - they don't keep anything else about (e.g. name) it so UserDefinedObject is no exception.

The answer is less to use the region UDO, but more 'what did you need to know anyway, since you can't differentiate between them once they're in the SG'. Since UDO is mainly useful for tracking SceneQuery results, it becomes largely useless as soon as something goes into a SG.

I think you're trying to solve the wrong problem. Think about why you need it, then think of another way to do it. Like collision / picking proxies for those things you need to still know about individually, or not adding things you need to identify individually to an SG, or something like that.
User avatar
zeroskill
Greenskin
Posts: 123
Joined: Wed Jul 20, 2005 8:30 pm
Contact:

Post by zeroskill »

Well, I'm using static geometry objects to hold certain level objects. Since these objects never move, there is no point of me keeping a non-visible entity/scenenode of it laying around. The static geometry objects only hold one instance of these items a piece, since they are rather large and there aren't that many of them in the first place. I've gotten around this situation by manually setting the UDO of each staticgoemetry region. (All one of them per static geometry.)

My concern was not of my own needs, I was able to get around the situation once genva pointed out that I could gain access to the regions. (Oversight on my part.)

The concern was that it seemed like a rather odd combination. In order for StaticGeometry regions to contain any useful UDO, they all have to contain the same one. Yet you have to set the region UDO's individually, implying that there may be a reason you would want them different. Yet individual entities added to a StaticGeometry do not retain their UDO's, and once an entity is added, you can't tell which regions the submeshes were assigned to.

I agree, it's not a bug, hence the quotes, but it does seem like a logical error. If it were my code base, I would add a function to assign the entire StaticGeometry object a single UDO, which is then copied to the regions as they are built. In my mind that would reflect some level of consistency.

I merely wanted to bring this oddity to attention (specifically your's Sinbad), and see if this was on purpose for some reason, or if it was an oversight. I say oversight, since UDOs are exposed by MoveableObject, which the regions inherit, and thus the UDO functionality might not have been considered at the time of implementation since it was not the primary concern. (Though I've already ran into a situation where it proves useful.)
User avatar
sinbad
OGRE Retired Team Member
OGRE Retired Team Member
Posts: 19269
Joined: Sun Oct 06, 2002 11:19 pm
Location: Guernsey, Channel Islands
x 66
Contact:

Post by sinbad »

It's completely consistent. UDO assignments relate directly to objects which can be individually identified. StaticGeometry::Region is the lowest level of detail that can be individually identified, therefore for it to have the UDO is correct. Personally I don't think a UDO on SG or SG::Region is very useful, but as you say Region inherits that ability, no matter how practical it is.

I fail to see how a single UDO for all SGs is useful. but if you want to do it, just iterate over the regions and assign them a single UDO after you hit SG::build. I'm loathe to promote this by adding a top-level feature because I fail to see the practical utility. Since Regions are still grouped in and of themselves, scene query results for them are not going to be that useful, even though strictly speaking you can use them.

There's a conflict here - you want to use a feature designed for identifying individual things in a class which specifically eradicates identity through batching. It's that requrement which I think is inconsistent, not the SG implementation.
User avatar
zeroskill
Greenskin
Posts: 123
Joined: Wed Jul 20, 2005 8:30 pm
Contact:

Post by zeroskill »

Basically, the primary use is to allow StaticGeometry to return useful SceneQuery results. It's one thing to know that you hit something, but knowing what you hit comes in handy quite often. Not every item that a user cares to get relevant SceneQuery results from is guaranteed to be in a scene node.

Here's an example:
It's like the bouncing ball demo using BSPs. You test for a physics collision to determine if the ball needs to change direction. If you could tell that you hit a block of rubber instead of a wall, you could reduce the inertia loss. But, since that block of rubber never moves, we just put it in a StaticGeometry, and since StaticGeometry doesn't have a UDO we can't tell if we actually hit it.

You could put another block of rubber in an Entity, in a SceneNode, and make it non-visible and place it in the same position as that StaticGeometry block of rubber. But, this assumes that there is only one block of rubber. If we have, say, a thousand of these all in a single StaticGeometry object, then you would need a thousand SceneNodes to represent them all. All of this added memory overhead, and depending on the algorithm for SceneQuery()'s in use, could make those functions take much longer than necessary, as there are many more objects to evaluate.

Obviously StaticGeometry Regions have a UDO (as an unintentional side effect), but I left that out to show that if you never had that unintentional feature available, certain scenes would be less feasible.

It really doesn't matter to me at this point. I've made my case, you've heard it, it's your engine, your decision. I'm just glad that UDOs are available to StaticGeometry since I have a valid use for them in my code. I just thought I would bring up a feature that was harder to use than it needed to be. Looks like I just found out it was never supposed to be there in the first place. I hope it doesn't go away, I hate managing patch sets to preserve functionality. :D
genva
OGRE Retired Team Member
OGRE Retired Team Member
Posts: 1603
Joined: Wed Oct 20, 2004 7:54 am
Location: Beijing, China
x 1

Post by genva »

For the example you given, a special collision detect library will work more perfectly. I don't think Ogre scene queries can fit physics system requirement like that (and it isn't design for that). Most Ogre users lost here, because they doesn't introduce other physics/collision detect library to dealing with game logic, but use Ogre scene queries as is :?.
User avatar
zeroskill
Greenskin
Posts: 123
Joined: Wed Jul 20, 2005 8:30 pm
Contact:

Post by zeroskill »

Very true, genva.

My specific use has to do with exact location picking on static geometry based off manual meshes. So a physics engine isn't going to help me there. Attaching UDOs to the static geometry, however, proves very useful for me. It allows me to localize my raycasting to a single entity, so I'm saving a ton of time as I don't have to evaluate every single polygon I have loaded. I can instead focus on a subset, which I happily provide a pointer to via UDOs. :)
User avatar
sinbad
OGRE Retired Team Member
OGRE Retired Team Member
Posts: 19269
Joined: Sun Oct 06, 2002 11:19 pm
Location: Guernsey, Channel Islands
x 66
Contact:

Post by sinbad »

It's also worth saying that StaticGeometry is not supposed to be a replacement for proper world geometry. It's very good at doing lots of detail geometry, and as a stand-in for real world geometry where you can't do it properly, or don't need to, but the fact is that it doesn't allow you the flexibility of true world geometry. Nor is it supposed to.

A good, modern world geometry system keeps 2 sets of data - one for visual, and one for collision, since the two requirements are actually quite different. For visuals you want to use large groups, batched up as best you can whilst still keeping the appropriate level of culling because the visual system needs coarse divisions. For collision you want a much more detailed structure. Both can be derived from the same input data but are derived into 2 different structures. StaticGeometry is a visual batcher - if you want to keep the detail for collision, you have to do it yourself or use real world geometry designed to return WorldFragments from queries.
User avatar
zeroskill
Greenskin
Posts: 123
Joined: Wed Jul 20, 2005 8:30 pm
Contact:

Post by zeroskill »

sinbad wrote:It's also worth saying that StaticGeometry is not supposed to be a replacement for proper world geometry. It's very good at doing lots of detail geometry, and as a stand-in for real world geometry where you can't do it properly, or don't need to *snip*
Key phrase there is "don't need to", and that is exactly what applies in my situation. Octree handles the groups of StaticGeometry more than well enough for my needs. If I were to rewrite everything to provide true "world geometry", I would end up reimplementing an Octree and sending the exact same data down the render queue. I see no good reason to reinvent the wheel when the one I have works perfectly fine.

You are right on the separate data for visual and collision. Which is exactly why I use UDOs in StaticGeomtry. I've created my own RaySceneQuery which runs the built in OctreeRaySceneQuery, and then checks the results for hits on the special StaticGeometry by looking for UDOs. For every one it finds, it re-runs the ray cast on a subset of data. If it finds a true hit (meaning it didn't just hit the bounding volume, but actually miss the polys within) then it will provide valid worldFragment data. In the end I have an efficient method of performing scene queries that return exact intersections on objects of a known type. It would almost be foolish for me to have a second octree of my own to hold repetitous data, and then waste time during scene queries by casting a ray down that data only to find that: yes I really do hit that same bounding volume in my data as well.

Sinbad, you're making a valid point on why it's a good idea to have separate collision data from visual data, which I do, but you've lost sight of the fact that it makes perfect sense to attach your collision data to your visual data. Quite often the visual culling algorithm is the same one used to cull data for ray casting. You're just looking for more detailed information when you perform a collision ray cast, so it makes perfect sense to merely drill deeper for collisions than you do for drawing.
klauss
Hobgoblin
Posts: 559
Joined: Wed Oct 19, 2005 4:57 pm
Location: LS87, Buenos Aires, República Argentina.

Post by klauss »

I have to agree with Sinbad.
There's no clean or easy way to generically accomplish what you did. Yours is a very special case.
Since entities may be added to any region at build time, there's no way of assigning UDOs that will make sense, without internal knowledge about the UDOs themselves: what to do when two entities with different UDOs are assigned to the same region?
In your case, you probably don't meet this unfortunate condition, since your UDOs I guess are more per-material rather than per-entity... but that's not the generic case, so Ogre itself can't decide what to do - only you.

An option... perhaps... would be to provide a StaticGeometry::BuildListener callback interface, with perhaps:

Code: Select all

class BuildListener
{
   virtual preAttachSubEntityToRegion(Entity *ent, SubEntity *sent, Region *rgn)=0;
   virtual postAttachSubEntityToRegion(Entity *ent, SubEntity *sent, Region *rgn)=0;
}
...that's the only pallatable option I see...
Oíd mortales, el grito sagrado...
Hey! What is it with that that?
Wing Commander Universe
User avatar
zeroskill
Greenskin
Posts: 123
Joined: Wed Jul 20, 2005 8:30 pm
Contact:

Post by zeroskill »

@Klauss:
That idea is actually worth some merit. Originally I was typing out a post against it, but after thinking it through I can see the advantage of maintaining a list of entities (and their submeshes) that originally made up the contents of the region. That would give you a very short list of submeshes to collision test against.

But, Sinbad, also has made good points. I may argue with the man on certain points, but I never intend to target his credibility (however heated the arguments get). Specifically, he's downright against StaticGeometry ever being used to represent world geometry. The problem with this idea is that it is a matter of context. In BSPs, StaticGeometry makes a horrible world data structure. In Octrees, it ends up being a perfect representation of world data (the visual stage data anyhow) if you attach a single entity to each StaticGeometry.

Honestly I think the best solution would be to comprimise. Extend the Octree SceneManager as a whole and add an OctreeWorldGeometry data type. It would behave much like StaticGeometry in that it maintains a non-movable, pretransformed, set of data to speed rendering, but it is built off of a single entity alone, rather than how StaticGeometry supports multiple entities. It makes sense to avoid defining generic world geometry objects in many scene managers, as most of them require some form of precalculation that is rather time consuming, and you cannot easily determine the correct attach point for a submesh in real time as it may actually work best if it is split apart and spread across several points in the world geometry data tree. Octrees, on the other hand, build fairly quickly from simple axis aligned bounding volumes, and the best location within the Octree for any random bounding volume is quick and rather painless.

There are certain tricks to making Octrees more efficient by ensuring that your goemetry fits nicely within the smallest possible bounding volume with no overlap, but they still work fairly well given random data (providing that the random data fits within the root volume). If reliable performance is a real concern, then a function could be added to evaluate the current OctreeWorldGeometry data and determine the best size and recursion depth of the Octree, and rebuild using that information. You really can't prevent users from doing stupid things (like making one big, high poly count submesh that covers the entire level) but it is possible to make a best effort to correct their mistakes.

The point is, I'm not going to argue about this any longer. I fully understand his concerns, and I agree with his points when I look at the generic concept of StaticGeometry. I only disagree when taken in the context of Octrees, and for that I believe the only true solution is to create a new object type specifically for the Octree SceneManager.
User avatar
sinbad
OGRE Retired Team Member
OGRE Retired Team Member
Posts: 19269
Joined: Sun Oct 06, 2002 11:19 pm
Location: Guernsey, Channel Islands
x 66
Contact:

Post by sinbad »

Specifically, he's downright against StaticGeometry ever being used to represent world geometry.
Actually I'm not - like I said, you can do it in certain specific cases. What I'm against is adding to the interface in such a way that suggests that certain constant behaviour can be relied upon (like consistent mapping of UDOs), which in fact only applies in a subset of cases. I'm a big fan of designing interfaces that are intuitive and do what they imply, so I really don't like adding something that only works in some limited cases. It has to work across the board, or in the majority of cases, or it doesn't belong in the interface of something that general.

About octree specialisation, DotSceneOctree already manages pre-baked chunks of geometry; never used it myself but I know some people do. Might be worth checking out.
User avatar
zeroskill
Greenskin
Posts: 123
Joined: Wed Jul 20, 2005 8:30 pm
Contact:

Post by zeroskill »

Ah! You changed your post between the time I read it and when I decided to post a reply. That's alright.

The thing that I'd like to know is, how would you react if a patch were to surface that added a reliable object type to represent scene geometry specifically for OctreeSceneManager. This would be a specialized class that is only available for OctreeSceneManager, as I don't exactly have tons of time to dedicate as it is and Octree is the only scene manager that directly relates to what I am doing with Ogre.

Would you be for or against such a scene manager specific patch?
User avatar
sinbad
OGRE Retired Team Member
OGRE Retired Team Member
Posts: 19269
Joined: Sun Oct 06, 2002 11:19 pm
Location: Guernsey, Channel Islands
x 66
Contact:

Post by sinbad »

It would have to be part of the Octree plugin, and would have to integrate through the 'setWorldGeometry' call - just be slightly careful since TerrainSceneManager subclasses Octree and implements that too, so any patch should allow both terrain and this to coexist. Otherwise it sounds fine.
User avatar
zeroskill
Greenskin
Posts: 123
Joined: Wed Jul 20, 2005 8:30 pm
Contact:

Post by zeroskill »

I'm a little fuzzy as to how integration through setWorldGeometry would work. I was thinking that it would be treated like a specialized version of StaticGeometry. Not inherited from that, just functionally similar with key exceptions. If that is how it is going to work, then that would mean the user is expected to define the content of these object through the use of entities. Given that, just what exactly would setWorldGeometry be expected to do? Create the entities based on the previously used mesh/material names, and then assign them to the world geometry objects and get them in the right position/orientation?

That one is going to take some thought. I'll see if I can work out something logical a bit later. Probably have to add a saveWorldGeometry function, or something with a similar goal. I guess we'll just see what comes out of it when I get the time allocated to implement it.
Post Reply