Vespers3D: Visibility Issues in 3D
by Rubes · 08/06/2007 (10:48 am) · 15 comments
Vespers3D: Visibility Challenges
Recap:
Vespers3D is our attempt to bring old-school text-based adventure games (interactive fiction) into the world of real-time first-person 3D - a new genre we are calling 3D/if (3D interactive fiction). It is based on Vespers, Jason Devlin's fantastic text IF game that won numerous awards from the IF community, including Best Game at the IFComp'05 and the 2006 XYZZY awards.
Although I've been focusing on introducing NPCs lately, I'd also like to take a moment to describe one of the big challenges I'm having as I move from a text environment to a graphic environment, and in doing so ask for some suggestions for possible solutions.
In text-based interactive fiction games, worlds are divided into individual, explicit "rooms" or locations. Each location has within it a set of world objects which are able to be referenced by the player. These objects (which also includes whatever items are currently in the player's inventory) are referred to as being "in scope". It's a fairly simple matter to collect a list of all objects that are currently in scope in a text game, and the player can "see" each of these objects unless explicitly designated (e.g., a coin inside a closed box would be considered in scope but not visible or accessible).
In 3D graphics games, of course, we have to deal with three-dimensional space, so we now also have to consider line of sight, among other things. Take, for instance, this example of a screenshot from Vespers3D:
Figure 1. Screenshot demonstrating problems with line-of-sight detection.
In this shot, I have selected the bed in the background to try and "examine" it. The response from the engine is that "You can't find any such thing," even though it's visibly right there. As you might imagine, a ray cast from the player's eye to the bed object first intersects Constantin (either his knife or the hare), so the bed is not considered to be "visible". How to best deal with this situation?
The figure below demonstrates the normal situations with respect to visibility testing, which forms the basis of our visibility checking routines:
Figure 2. The normal visibility detection situations.
However, as in the above screenshot, there are situations where an object is technically visible to the person playing the game, but not to the engine. These are shown below in examples #4 and #5:
Figure 3. Issues with visibility detection in certain situations.
The screenshot from the game is similar to example #4 above; we can also have a situation like #5 if we step just outside the doorway to Constantin's Room. The problem is that it's hard for the engine to know the difference between a situation like #5 and one like #3. As far as I can tell, the engine doesn't necessarily know that the object is rendered in a way that is visible to the person playing the game. There may be ways to know that, but I'm not familiar with them.
But there are other situations as well. Take #6, for example. If the player tried to examine the object in #6, the engine would think that the problem is that it is blocked from view by the other object, not the wall. There needs to be a way to know the difference between situation #4 and situation #6, where the target object is partly visible in one situation but not the other.
But wait, there's more!
Figure 4. More issues with visibility detection.
Example #7 above is similar to example #4, but when the target and blocking objects are in a different room than the player. I had thought to maybe use the target/blocking objects' room (compared with the player's room) as a potential solution, but then you have situations like #7 where that doesn't work.
Finally, you have example #8, where the target object is blocked by a closed door. This situation is very similar to example #4, but here the blocking object is a door (a DTS object, not an interior) which completely obscures the target object from view. How can the engine know the difference between example #4 (where the target is blocked by a DTS but is still visible) and example #8 (where the target is blocked by a DTS but is not visible)?
A call for suggestions
I haven't yet come up with a good solution for this problem, and unfortunately it results in some awkward situations while playing -- players can't examine objects that are clearly visible, or they can't manipulate an object that is basically right in front of them. It forces players to repeat their action after shifting a little bit to one side or another, which is not a big deal, but it's still an annoyance. And that's something I'd like to avoid if possible.
I've considered various options, but no one solution seems to account for all situations. I could, for instance, perform a raycast and then repeat it if it returns a DTS object, exempting that DTS object from the second raycast. That would tell me if two DTS objects are blocking the target, or a DTS and an interior, and that might at least give me a good excuse for saying the target is "not visible enough." But then you have the situation like #8, which causes problems with that. And in the initial screenshot above, the bed is blocked by both the knife and the hare -- two DTS objects, even though the bed is still fairly visible.
The main issue is coming up with a response from the engine that takes into account whether or not the target object is visible to any extent to the person playing the game. Whether or not that can be done is a good question. But also, to what extent does the target need to be visible? How much should be visible to consider it visible enough? That's a tough question, and I'm not even sure that can be addressed.
Just some more of the pain as we evolve from text to graphics. I'd be happy to hear some thoughts or suggestions from the community on this one.
Recap:
Vespers3D is our attempt to bring old-school text-based adventure games (interactive fiction) into the world of real-time first-person 3D - a new genre we are calling 3D/if (3D interactive fiction). It is based on Vespers, Jason Devlin's fantastic text IF game that won numerous awards from the IF community, including Best Game at the IFComp'05 and the 2006 XYZZY awards.
Although I've been focusing on introducing NPCs lately, I'd also like to take a moment to describe one of the big challenges I'm having as I move from a text environment to a graphic environment, and in doing so ask for some suggestions for possible solutions.
In text-based interactive fiction games, worlds are divided into individual, explicit "rooms" or locations. Each location has within it a set of world objects which are able to be referenced by the player. These objects (which also includes whatever items are currently in the player's inventory) are referred to as being "in scope". It's a fairly simple matter to collect a list of all objects that are currently in scope in a text game, and the player can "see" each of these objects unless explicitly designated (e.g., a coin inside a closed box would be considered in scope but not visible or accessible).
In 3D graphics games, of course, we have to deal with three-dimensional space, so we now also have to consider line of sight, among other things. Take, for instance, this example of a screenshot from Vespers3D:
Figure 1. Screenshot demonstrating problems with line-of-sight detection.In this shot, I have selected the bed in the background to try and "examine" it. The response from the engine is that "You can't find any such thing," even though it's visibly right there. As you might imagine, a ray cast from the player's eye to the bed object first intersects Constantin (either his knife or the hare), so the bed is not considered to be "visible". How to best deal with this situation?
The figure below demonstrates the normal situations with respect to visibility testing, which forms the basis of our visibility checking routines:
Figure 2. The normal visibility detection situations.However, as in the above screenshot, there are situations where an object is technically visible to the person playing the game, but not to the engine. These are shown below in examples #4 and #5:
Figure 3. Issues with visibility detection in certain situations.The screenshot from the game is similar to example #4 above; we can also have a situation like #5 if we step just outside the doorway to Constantin's Room. The problem is that it's hard for the engine to know the difference between a situation like #5 and one like #3. As far as I can tell, the engine doesn't necessarily know that the object is rendered in a way that is visible to the person playing the game. There may be ways to know that, but I'm not familiar with them.
But there are other situations as well. Take #6, for example. If the player tried to examine the object in #6, the engine would think that the problem is that it is blocked from view by the other object, not the wall. There needs to be a way to know the difference between situation #4 and situation #6, where the target object is partly visible in one situation but not the other.
But wait, there's more!
Figure 4. More issues with visibility detection.Example #7 above is similar to example #4, but when the target and blocking objects are in a different room than the player. I had thought to maybe use the target/blocking objects' room (compared with the player's room) as a potential solution, but then you have situations like #7 where that doesn't work.
Finally, you have example #8, where the target object is blocked by a closed door. This situation is very similar to example #4, but here the blocking object is a door (a DTS object, not an interior) which completely obscures the target object from view. How can the engine know the difference between example #4 (where the target is blocked by a DTS but is still visible) and example #8 (where the target is blocked by a DTS but is not visible)?
A call for suggestions
I haven't yet come up with a good solution for this problem, and unfortunately it results in some awkward situations while playing -- players can't examine objects that are clearly visible, or they can't manipulate an object that is basically right in front of them. It forces players to repeat their action after shifting a little bit to one side or another, which is not a big deal, but it's still an annoyance. And that's something I'd like to avoid if possible.
I've considered various options, but no one solution seems to account for all situations. I could, for instance, perform a raycast and then repeat it if it returns a DTS object, exempting that DTS object from the second raycast. That would tell me if two DTS objects are blocking the target, or a DTS and an interior, and that might at least give me a good excuse for saying the target is "not visible enough." But then you have the situation like #8, which causes problems with that. And in the initial screenshot above, the bed is blocked by both the knife and the hare -- two DTS objects, even though the bed is still fairly visible.
The main issue is coming up with a response from the engine that takes into account whether or not the target object is visible to any extent to the person playing the game. Whether or not that can be done is a good question. But also, to what extent does the target need to be visible? How much should be visible to consider it visible enough? That's a tough question, and I'm not even sure that can be addressed.
Just some more of the pain as we evolve from text to graphics. I'd be happy to hear some thoughts or suggestions from the community on this one.
#2
Thanks, Phil, I appreciate the suggestion. I'm a bit confused by what you mean here, though. Do you mean the raycast should start at the camera and extend from there through the screen position occupied by the cursor into the world? This is pretty much how object selection occurs to begin with.
If that's what you mean, though, there are still two situations which would cause problems with that.
The first is that object selection allows the player to click on a target to select it, but then he can move the cursor around while still maintaining object selection. So a player could click on a target, move the cursor somewhere else, and then later type "EXAMINE" to look at the selected object later on.
The other situation is that players can refer to objects without having to click on them. Since I incorporate text input, players at any time could type "EXAMINE TARGET", even if the target object is behind a wall or isn't anywhere nearby. The engine would then have to find where the object is, and then determine if it is visible. So where would a raycast begin and end in that instance?
08/06/2007 (11:27 am)
Quote:Typically for this, you would do a raycast not from the eyepoint, but from the "cursor point", that is, from the position on the screen that is cast from the camera position (imagine it being behind the screen) through the screen plane (the cursor point lies in this plane) and extends out into the world.
Thanks, Phil, I appreciate the suggestion. I'm a bit confused by what you mean here, though. Do you mean the raycast should start at the camera and extend from there through the screen position occupied by the cursor into the world? This is pretty much how object selection occurs to begin with.
If that's what you mean, though, there are still two situations which would cause problems with that.
The first is that object selection allows the player to click on a target to select it, but then he can move the cursor around while still maintaining object selection. So a player could click on a target, move the cursor somewhere else, and then later type "EXAMINE" to look at the selected object later on.
The other situation is that players can refer to objects without having to click on them. Since I incorporate text input, players at any time could type "EXAMINE TARGET", even if the target object is behind a wall or isn't anywhere nearby. The engine would then have to find where the object is, and then determine if it is visible. So where would a raycast begin and end in that instance?
#3
Phil's idea is a good one, but possibly too technical to grasp at first read. If I read his idea correctly, what he is basically saying is that you do two 'renders'--one that goes to the video card, and one that is simply creating a dynamic but simplified version (one unique color per object) of the scene itself. With no blending, you could basically sample the "color" of whatever object is at the cursor position (mapped to the virtual representation of course), and then match this unique color of an object to the object itself--in effect, using the concept of render layers to do your visibility check for you.
A second approach would be to isolate your selection from the scene management. A lot more overhead for this type of approach, but basically you would track meta-information about which objects in a particular scene are selectable, and actually be able to do some nifty scripted checks to the selectability of objects--for example, if you have a body that shows a hilt of a dagger, you could script it such that the person needs to draw the dagger before they can examine it--something that can be much more difficult to implement with a pure raycast solution.
With this second option, you could do a "continued ray cast" that returns a list of all objects at a certain screen position (regardless of occlusion), and then check the meta-information on those objects to determine if they are selectable at that time. Possibly you could also have a GUI popup that lists all objects returned, and let them select which one is most important to them at that time.
08/06/2007 (11:52 am)
Given the nature of 3D scene representations, and the concept that a bounding box isn't guaranteed to be a fully accurate collision check, you can get stuck in exactly the scenarios you describe.Phil's idea is a good one, but possibly too technical to grasp at first read. If I read his idea correctly, what he is basically saying is that you do two 'renders'--one that goes to the video card, and one that is simply creating a dynamic but simplified version (one unique color per object) of the scene itself. With no blending, you could basically sample the "color" of whatever object is at the cursor position (mapped to the virtual representation of course), and then match this unique color of an object to the object itself--in effect, using the concept of render layers to do your visibility check for you.
A second approach would be to isolate your selection from the scene management. A lot more overhead for this type of approach, but basically you would track meta-information about which objects in a particular scene are selectable, and actually be able to do some nifty scripted checks to the selectability of objects--for example, if you have a body that shows a hilt of a dagger, you could script it such that the person needs to draw the dagger before they can examine it--something that can be much more difficult to implement with a pure raycast solution.
With this second option, you could do a "continued ray cast" that returns a list of all objects at a certain screen position (regardless of occlusion), and then check the meta-information on those objects to determine if they are selectable at that time. Possibly you could also have a GUI popup that lists all objects returned, and let them select which one is most important to them at that time.
#4
Your second approach is interesting to me, but I already do this to a certain extent. For instance, in Vespers we have an alms box that has a coin inside of it. With the box closed, you can't see the coin. So I use a form of metadata in script to specify that (a) the box is currently closed, and (b) the coin is inside a closed box and is therefore concealed. So trying to select or examine the coin returns false in that situation; opening the box then sets the coin's concealed field to false, so it can now be selected and examined.
I'm not sure how that addresses some of the situations above, though, like the one in the screenshot. The bed is selectable, since selection does utilize a raycast from the camera through the cursor position.
Visibility is a different issue, though, because it does not incorporate cursor position. A player could select the bed, move around the room, and later decide to examine it by hitting the X key -- when the cursor could be way off somewhere else. Plus, as mentioned above, players can just type "EXAMINE BED" without using the cursor in any way...so how would a raycast work in that situation?
By the way...how could a ray cast return all objects at a certain screen position? Doesn't it just return the first object it collides with?
08/06/2007 (12:11 pm)
@Stephen: Thanks for the suggestion as well. Phil's suggestion is a bit technical for me to grasp right now, but your explanation helps some.Your second approach is interesting to me, but I already do this to a certain extent. For instance, in Vespers we have an alms box that has a coin inside of it. With the box closed, you can't see the coin. So I use a form of metadata in script to specify that (a) the box is currently closed, and (b) the coin is inside a closed box and is therefore concealed. So trying to select or examine the coin returns false in that situation; opening the box then sets the coin's concealed field to false, so it can now be selected and examined.
I'm not sure how that addresses some of the situations above, though, like the one in the screenshot. The bed is selectable, since selection does utilize a raycast from the camera through the cursor position.
Visibility is a different issue, though, because it does not incorporate cursor position. A player could select the bed, move around the room, and later decide to examine it by hitting the X key -- when the cursor could be way off somewhere else. Plus, as mentioned above, players can just type "EXAMINE BED" without using the cursor in any way...so how would a raycast work in that situation?
By the way...how could a ray cast return all objects at a certain screen position? Doesn't it just return the first object it collides with?
#5
i had a similar visibility issue come up for performance reasons.
we have scenes sometimes with many player objects which are potentially obscured by a large frying pan.
rendering player objects is expensive because of mesh skinning, so when they're behind the frying pan i want to not render them at all.
the solution i came up with was to raycast to multiple points in the object.
in my case i chose to cast to five points: the center and the four points around it,
altho you could also choose all 6 corners of the bounding box and be okay.
i was worried about the performance hit of this,
so additionally i only do the raycast every N frames.
this has worked pretty well,
and you have to get the camera in a pretty specific situation such as looking thru a ladder or somesuch before it falls apart.
here's a pic of where i cast to:

i wonder if you could do something with a pixel shader along Phil's suggestion
where each time you draw a pixel:
1) before drawing the pixel, get the value in the stencil buffer. call it id1.
2) after drawing the pixel, write the "special ID" of the current object into the stencil buffer. call that id2.
3) in an array somewhere, decrement array[id1] and increment array[id2].
then after the entire scene has been drawn, if array[id2] > 0, then you know at least one pixel of your object is visible on screen.
this won't work of course for partially transparent objects.
PS - really nice diagrams, btw!
08/06/2007 (2:22 pm)
Rubes -i had a similar visibility issue come up for performance reasons.
we have scenes sometimes with many player objects which are potentially obscured by a large frying pan.
rendering player objects is expensive because of mesh skinning, so when they're behind the frying pan i want to not render them at all.
the solution i came up with was to raycast to multiple points in the object.
in my case i chose to cast to five points: the center and the four points around it,
altho you could also choose all 6 corners of the bounding box and be okay.
i was worried about the performance hit of this,
so additionally i only do the raycast every N frames.
this has worked pretty well,
and you have to get the camera in a pretty specific situation such as looking thru a ladder or somesuch before it falls apart.
here's a pic of where i cast to:

i wonder if you could do something with a pixel shader along Phil's suggestion
where each time you draw a pixel:
1) before drawing the pixel, get the value in the stencil buffer. call it id1.
2) after drawing the pixel, write the "special ID" of the current object into the stencil buffer. call that id2.
3) in an array somewhere, decrement array[id1] and increment array[id2].
then after the entire scene has been drawn, if array[id2] > 0, then you know at least one pixel of your object is visible on screen.
this won't work of course for partially transparent objects.
PS - really nice diagrams, btw!
#6
I'd like to stay away from pixel shaders if possible, but actually, you bring up a method I had been pondering: raycasting to the corners of the bounding box (wouldn't that be 8 corners?). I'll think about that one for a bit and see if it can get the job done, but I think it might.
08/06/2007 (2:35 pm)
@Orion: A large frying pan, you say? How interesting. Looks like I picked the right icon for my diagrams!I'd like to stay away from pixel shaders if possible, but actually, you bring up a method I had been pondering: raycasting to the corners of the bounding box (wouldn't that be 8 corners?). I'll think about that one for a bit and see if it can get the job done, but I think it might.
#7
bounding box - woops, yeah, 8 corners !
i'm currently using an approximation of the 2D screen-aligned bounding rectangle,
but i think the good old 3D bounding box should be fine too, it was faster than i expected.
08/06/2007 (2:40 pm)
yeah, i'd stay away from pixels shaders if possible too.bounding box - woops, yeah, 8 corners !
i'm currently using an approximation of the 2D screen-aligned bounding rectangle,
but i think the good old 3D bounding box should be fine too, it was faster than i expected.
#8
Is there a way to get the bounding box that conforms to the shape itself, not the world axis?
08/06/2007 (7:15 pm)
I've been working at this, and I think checking the bounding box might work. The problem is that the worldBox (returned by %object.getWorldBox) is not the box I want. The worldBox is the bounding box confined to the world axis, which means that objects that are rotated will have worldBoxes that might be way off from the shape itself.Is there a way to get the bounding box that conforms to the shape itself, not the world axis?
#9
08/06/2007 (9:21 pm)
As well as checking the items that are visible with the ray cast, include any selected items as well (ie. the bed) in the visible list. That way you can examine selected items as well as visible ones.
#10
08/06/2007 (9:51 pm)
@ChrisG: True, but the point is that selected objects may not necessarily be visible. An object can be selected, after which the player can move around such that the object become hidden by another object. The important question is, which objects are visible at the time the 'examine' command is given, not when the object is selected.
#11
you might look into doing this stuff in the engine versus script, i think it's easier to get at the object-aligned bounding boxes in there, via getTransform() and the bounding box and mScale. however if you do want to do it in script, the following functions might be handy -
%obj.localToWorldPoint("0 0 0") yields one corner of the local bounding box, and %obj.localToWorldPoint("1 1 1") yields the diagonal, etc, with scale accounted for.
note - these work well for Triggers. i haven't tested them w/ other objects. the line with "bummer.." might only apply to triggers, not sure. i've been meaning to submit these as a resource but haven't because of the weirdness with the "bummer" lines and also not being totally convinced of the corresponding function for transforms.
08/06/2007 (10:22 pm)
hey rubes -you might look into doing this stuff in the engine versus script, i think it's easier to get at the object-aligned bounding boxes in there, via getTransform() and the bounding box and mScale. however if you do want to do it in script, the following functions might be handy -
%obj.localToWorldPoint("0 0 0") yields one corner of the local bounding box, and %obj.localToWorldPoint("1 1 1") yields the diagonal, etc, with scale accounted for.
note - these work well for Triggers. i haven't tested them w/ other objects. the line with "bummer.." might only apply to triggers, not sure. i've been meaning to submit these as a resource but haven't because of the weirdness with the "bummer" lines and also not being totally convinced of the corresponding function for transforms.
// note that this is a POINT, not a vector.
function SceneObject::localToWorldPoint (%this, %pnt)
{
%mat = %this.getTransform ();
%pnt = setWord(%pnt, 1, getWord(%pnt, 1) - 1); // bummer about this.
%pnt = vectorConvolve (%pnt, %this.getScale());
%pnt = MatrixMulPoint (%mat, %pnt);
return %pnt;
}
// note that this is a POINT, not a vector.
function SceneObject::worldToLocalPoint (%this, %pnt)
{
%mat = %this.getWorldTransform();
%pnt = MatrixMulPoint (%mat, %pnt);
%pnt = vectorConvolveInverse (%pnt, %this.getScale());
%pnt = setWord(%pnt, 1, getWord(%pnt, 1) + 1); // bummer about this.
return %pnt;
}
#12
If this is not the case, please ignore the rest of this post.
If an object is visible, it can be selected via the cursor which requires a ray cast from the cursor position in world coordinate system rather than from the camera position. In this case, your bed example would not pose a problem, it would just require that the player position the cursor over a part of the bed that is not occluded.
The object thus selected should now have the focus even if the player looks away. You could enhance the controls by having the avatar turn towards the object when the examine command is issued so that it is actually visible.
If you keep the adventure semantic, your examine command need not use a ray cast, your game logic handles this based on the list of interesting objects for the current location. If no object has focus you could still respond to the examine command by performing a line of sight test (from the camera position this time) for each known object at that location, asking the player which of the objects that passed the test they would like to examine. If this test reduces the number to 1, you do not even have to ask.
Even this test could be avoided if you just ask the player which of the known objects should be examined. Again the avatar could turn towards the object once chosen.
08/07/2007 (5:35 am)
If I have understood correctly, the objects that may be examined need not be visible as you have the adventure based semantic of objects in the current room. If this is not the case, please ignore the rest of this post.
If an object is visible, it can be selected via the cursor which requires a ray cast from the cursor position in world coordinate system rather than from the camera position. In this case, your bed example would not pose a problem, it would just require that the player position the cursor over a part of the bed that is not occluded.
The object thus selected should now have the focus even if the player looks away. You could enhance the controls by having the avatar turn towards the object when the examine command is issued so that it is actually visible.
If you keep the adventure semantic, your examine command need not use a ray cast, your game logic handles this based on the list of interesting objects for the current location. If no object has focus you could still respond to the examine command by performing a line of sight test (from the camera position this time) for each known object at that location, asking the player which of the objects that passed the test they would like to examine. If this test reduces the number to 1, you do not even have to ask.
Even this test could be avoided if you just ask the player which of the known objects should be examined. Again the avatar could turn towards the object once chosen.
#13
...which looks exactly like what you are doing in script. I'll probably reproduce this code somewhere (maybe in shapeBase) and add a console method to expose it to script, although I'll probably try yours out in script first to see how it performs. Thanks!
The next question, though, is how many corners must be directly visible for the target to be considered visible? What I'll probably do is first check for line-of-sight to the target's WorldBoxCenter point -- if that's clear, then the object is visible. If not, then maybe I'll check the 8 corners, and perhaps require 3 of them to be clear by line-of-sight to consider the target "visible enough"...
@Robert: Yes, you understood correctly...mostly.
The main problem with trying to use the IF-based system of sequestered rooms (and objects within those rooms) in the 3D world is that rooms are not as segregated as they are in IF. In IF, you can't look from one room into another, but you certainly can in 3D. Take example #7 above, for instance. The target is in a different room than the player, but if the player is standing right near the doorway, there's no reason the target should not be considered visible, unless you're in situation #8, where there is a door in between the player and the target.
This is true, and this is how object selection is currently performed. Two issues with that, though: (1) just because a sliver of the target is visible enough to select the object doesn't necessarily mean we should consider it "examinable", so to speak, and (2) the "examine" command (or any command to manipulate the target) can be performed at any time after the target is selected. In addition, players can examine or manipulate objects just by typing their name (EXAMINE DESK), even if they are not visible on screen at the time.
This assumes, however, that the player has not moved since selecting the object. The player could, of course, select the target and then move somewhere else before executing the examine command. Is the target still visible at that point?
As mentioned above, although I do use the typical adventure semantic, it's not quite the same since I do want to allow the examination or manipulation of objects that are nearby regardless of which "room" those objects are located in. So basically I keep track of which "selectable" objects are within a particular range of the player.
Also, if no object has focus and the player types EXAMINE, then the game will automatically respond with "What do you want to examine?" I would probably prefer that the player specify the object to examine by either selecting it with the mouse first, or by typing the name of the object with the examine command. That eliminates the need to figure it out for him.
08/07/2007 (8:08 am)
@Orion: Thanks, I think that should probably do it. I was looking into ways of getting the scaled and rotated object bounding box in C++, and I saw that this appears to be the process used by the world editor (from WorldEditor::renderObjectBox() in worldEditor.cc):EDIT: engine code snipped (forgot that blogs are exposed to the world)
...which looks exactly like what you are doing in script. I'll probably reproduce this code somewhere (maybe in shapeBase) and add a console method to expose it to script, although I'll probably try yours out in script first to see how it performs. Thanks!
The next question, though, is how many corners must be directly visible for the target to be considered visible? What I'll probably do is first check for line-of-sight to the target's WorldBoxCenter point -- if that's clear, then the object is visible. If not, then maybe I'll check the 8 corners, and perhaps require 3 of them to be clear by line-of-sight to consider the target "visible enough"...
@Robert: Yes, you understood correctly...mostly.
The main problem with trying to use the IF-based system of sequestered rooms (and objects within those rooms) in the 3D world is that rooms are not as segregated as they are in IF. In IF, you can't look from one room into another, but you certainly can in 3D. Take example #7 above, for instance. The target is in a different room than the player, but if the player is standing right near the doorway, there's no reason the target should not be considered visible, unless you're in situation #8, where there is a door in between the player and the target.
Quote:If an object is visible, it can be selected via the cursor which requires a ray cast from the cursor position in world coordinate system rather than from the camera position. In this case, your bed example would not pose a problem, it would just require that the player position the cursor over a part of the bed that is not occluded.
This is true, and this is how object selection is currently performed. Two issues with that, though: (1) just because a sliver of the target is visible enough to select the object doesn't necessarily mean we should consider it "examinable", so to speak, and (2) the "examine" command (or any command to manipulate the target) can be performed at any time after the target is selected. In addition, players can examine or manipulate objects just by typing their name (EXAMINE DESK), even if they are not visible on screen at the time.
Quote:The object thus selected should now have the focus even if the player looks away. You could enhance the controls by having the avatar turn towards the object when the examine command is issued so that it is actually visible.
This assumes, however, that the player has not moved since selecting the object. The player could, of course, select the target and then move somewhere else before executing the examine command. Is the target still visible at that point?
Quote:If you keep the adventure semantic, your examine command need not use a ray cast, your game logic handles this based on the list of interesting objects for the current location. If no object has focus you could still respond to the examine command by performing a line of sight test (from the camera position this time) for each known object at that location, asking the player which of the objects that passed the test they would like to examine. If this test reduces the number to 1, you do not even have to ask.
As mentioned above, although I do use the typical adventure semantic, it's not quite the same since I do want to allow the examination or manipulation of objects that are nearby regardless of which "room" those objects are located in. So basically I keep track of which "selectable" objects are within a particular range of the player.
Also, if no object has focus and the player types EXAMINE, then the game will automatically respond with "What do you want to examine?" I would probably prefer that the player specify the object to examine by either selecting it with the mouse first, or by typing the name of the object with the examine command. That eliminates the need to figure it out for him.
#14
Or only have items within a certain range be selectable and examinable. If necessary, have the select/examine range change in rooms where it's necessary (with trigger zone perhaps?). A larger room, like inside a chapel, could have larger selectable radius. Between the selection range, and raycasting for 3 corners of the bounding box. It should eliminate some of the problems.
I do see checking 3 corners of a bounding box being good for objects smaller than a desk. But if you are standing in a hallway peering into a room through the doorway, and trying to look at a large object, like a desk, you may be able to see the center of the desk easily, but the doorway would block off 5+ of the bounding corners.
08/09/2007 (12:25 pm)
You could incorporate a distance limit from the item to be examined. Entering "Examine Bed" after walking down the hall could return the message "The bed is not in range/too far to examine".Or only have items within a certain range be selectable and examinable. If necessary, have the select/examine range change in rooms where it's necessary (with trigger zone perhaps?). A larger room, like inside a chapel, could have larger selectable radius. Between the selection range, and raycasting for 3 corners of the bounding box. It should eliminate some of the problems.
I do see checking 3 corners of a bounding box being good for objects smaller than a desk. But if you are standing in a hallway peering into a room through the doorway, and trying to look at a large object, like a desk, you may be able to see the center of the desk easily, but the doorway would block off 5+ of the bounding corners.
#15
That's how it's currently done. I have a distance limit on specific verbs -- so you can examine objects that are within a certain range, but you can do other things (like 'take') only within a different/shorter range. The range for selecting objects is the largest, since selection is independent of the verb/action to be performed on that object. So you can select objects within a large radius, but you can only do certain things with them based on the distance away.
The time when issues are introduced is when a player selects an object but then does not perform an action on that object until later, potentially after the player has moved around to a different location (even if it's just a small distance away).
The problem with changing the selectable radius depending on the player's current room is that the player could be standing right outside the doorway of a large room, looking into it. That would potentially introduce an apparent inconsistency in behavior based only on a few pixels.
Generally speaking, this isn't be a problem. I've actually implemented it such that a check is first made to the target object's center -- if that is unobstructed, then the target is considered visible and no further checks are made. If it's obstructed, it then checks the 8 corners, and 3 need to be visible. This has, so far, proven to be pretty effective and fairly consistent with what appears on screen.
It does, however, depend on two things: (1) the object bounding boxes need to fairly tightly conform to the object's mesh -- if there is a lot of extra space between the object and the edges of its bounding box, then that introduces obstructions that don't appear to visually make sense; and (2) similarly, there can't be much extra space between the bottom of an object and the bottom of its bounding box -- if there is, then placing the object so that it appears to be resting on the ground or floor ends up automatically hiding the bottom 4 corners below the terrain or interior surface.
I can adjust a bit for #2 by adjusting the calculated bounding box a wee bit, but I'd rather not since that doesn't apply to all objects (such as those that are mounted on a wall, for example).
08/09/2007 (12:53 pm)
Quote:You could incorporate a distance limit from the item to be examined. Entering "Examine Bed" after walking down the hall could return the message "The bed is not in range/too far to examine".
Or only have items within a certain range be selectable and examinable. If necessary, have the select/examine range change in rooms where it's necessary (with trigger zone perhaps?). A larger room, like inside a chapel, could have larger selectable radius. Between the selection range, and raycasting for 3 corners of the bounding box. It should eliminate some of the problems.
That's how it's currently done. I have a distance limit on specific verbs -- so you can examine objects that are within a certain range, but you can do other things (like 'take') only within a different/shorter range. The range for selecting objects is the largest, since selection is independent of the verb/action to be performed on that object. So you can select objects within a large radius, but you can only do certain things with them based on the distance away.
The time when issues are introduced is when a player selects an object but then does not perform an action on that object until later, potentially after the player has moved around to a different location (even if it's just a small distance away).
The problem with changing the selectable radius depending on the player's current room is that the player could be standing right outside the doorway of a large room, looking into it. That would potentially introduce an apparent inconsistency in behavior based only on a few pixels.
Quote:
I do see checking 3 corners of a bounding box being good for objects smaller than a desk. But if you are standing in a hallway peering into a room through the doorway, and trying to look at a large object, like a desk, you may be able to see the center of the desk easily, but the doorway would block off 5+ of the bounding corners.
Generally speaking, this isn't be a problem. I've actually implemented it such that a check is first made to the target object's center -- if that is unobstructed, then the target is considered visible and no further checks are made. If it's obstructed, it then checks the 8 corners, and 3 need to be visible. This has, so far, proven to be pretty effective and fairly consistent with what appears on screen.
It does, however, depend on two things: (1) the object bounding boxes need to fairly tightly conform to the object's mesh -- if there is a lot of extra space between the object and the edges of its bounding box, then that introduces obstructions that don't appear to visually make sense; and (2) similarly, there can't be much extra space between the bottom of an object and the bottom of its bounding box -- if there is, then placing the object so that it appears to be resting on the ground or floor ends up automatically hiding the bottom 4 corners below the terrain or interior surface.
I can adjust a bit for #2 by adjusting the calculated bounding box a wee bit, but I'd rather not since that doesn't apply to all objects (such as those that are mounted on a wall, for example).

Torque 3D Owner Phil Carlisle
In theory, that should ALWAYS return the correct object, but it might fail in some cases because you have bounding volumes that represent objects rather than thier polygonal geometry.
One alternative to this (I'd be surprised if this wasnt enough) would be to use selection buffers. Basically it involves rendering each object using a single colour value used as an "id" which writes that value to a buffer (say the stencil buffer). You then lookup the object using the id value in the buffer at that cursor position (so basically youre writing a constant value into a buffer, per screen pixel, which represents the lookup value of your selectable object). This works, but maybe not be ideal either (its a pain to track object id's and you will want to look at how many stencil bits are available to you, could be its only an 8 bit stencil buffer, so you'd have to be tricky about how many different id's can be used in any one visibility region.
Could be done similarly with shaders and render targets, but I've heard of selection buffers being used in older SGi style apps (have a look at "object picking" as a search).