DirectGui and render

Hi,

I am trying to add a DirectGui element at a position on the scene. But when i set the position (pos) as (5,0,0) i do not see the object positioned there. Upon looking at the manual , i understood that the elements are by default parented to aspect2d and hence have no effect.

But when i tried to reparent it to render and then set the pos keyword or used setPos, i did not see any object on the screen.

Here is the program i tried:


import direct.directbase.DirectStart
from direct.gui.OnscreenText import OnscreenText 
from direct.gui.DirectGui import *

#add some text
bk_text = "DirectOptionMenu Demo"
textObject = OnscreenText(text = bk_text, pos = (0.85,0.85), 
scale = 0.07,fg=(1,0.5,0.5,1),align=TextNode.ACenter,mayChange=1)

#add some text
output = ""
textObject = OnscreenText(text = output, pos = (0.95,-0.95),
 scale = 0.07,fg=(1,0.5,0.5,1),align=TextNode.ACenter,mayChange=1)

#callback function to set  text 
def itemSel(arg):
	output = "Item Selected is: "+arg
	textObject.setText(output)

#create a frame
menu = DirectOptionMenu(text="options", scale=0.1,items=["item1","item2","item3"],initialitem=2,
highlightColor=(0.65,0.65,0.65,1),command=itemSel)
menu.reparentTo(render)
menu.setPos(1,0,0)

base.camera.setPos(0,10,0)
#run the tutorial
run()

If there is no way i can set a direct UI object in a 3d world , then why does the pos parameter in the constructor take 3 parameters?

Also, when menu’s pos is set in the constructor as :


menu = DirectOptionMenu(text="options", scale=0.1,items=["item1","item2","item3"],initialitem=2,
highlightColor=(0.65,0.65,0.65,1),command=itemSel,
pos=(-1.5,2,1)

the menu is placed at that position in the corner of the screen. But i am unable to navigate to the node using the mouse beyond the value of 1 for the z in the pos parameter . The mouse does not work as it would for models. Is this an expected behaviour?

Am i missing something here about Direct Gui? Or is this a limitation of UI? I am using panda 1.1 ion debian.

Also, is it possible to place a direct ui element at a 3d position in the screen say at (50,0,0) like any other panda node?(Since it is a NodePath it should be, but it doesnot seem to work). Please advise me on how i can set a direct UI element at some point in a scene.

You can certainly parent a DirectGui object to render if you like. It will show up wherever you put it. In your above example, however, you have positioned the camera to (0, 10, 0)–10 units in front of your DirectObjectMenu. You probably meant to set the camera pos to (0, -10, 0) instead.

Of course, if you parent a DirectGui object to render, you won’t be able to interact with it. The DirectGui system is intended for 2-d interactions, and the DirectGui objects need to be parented under aspect2d in order for the mouse interaction to work.

I don’t understand what you mean by “i understood that the elements are by default parented to aspect2d and hence have no effect.” Everything works as usual under aspect2d; you just don’t have a meaningful Y dimension there. You can set the X and Z coordinates to any position you like, within the range (-1.333, 0, -1) to (1.333, 0, 1), which are the dimensions of the screen. Certainly if you position your object to (5, 0, 0), you won’t see it, since that’s 3.6666 units past the right edge of the screen.

The pos parameter in most DirectGui constructors takes 3 parameters mainly because NodePath.setPos() takes 3 parameters. But the Y dimension isn’t much used and is usually left at 0 (although there are cases in which it does have meaning).

I am completely unable to interpret the sentences “But i am unable to navigate to the node using the mouse beyond the value of 1 for the z in the pos parameter . The mouse does not work as it would for models.” The mouse coordinates are returned in the range (-1, -1) to (1, 1). It is true they do not move beyond the value of 1, but 1 is the edge of the screen. And I’m afraid I don’t know what you could be referring to with “The mouse does not work as it would for models.” Could you elaborate, please?

David

Yes, that was a mistake. i fixed it.

I understood this part. Now if i have, some 2D nodes parented to render, how can i interact with them? Should i be using picking objects way?I am trying to build something like a unix terminal into a 3D world.

  • It should just display some lines of text.
  • When the user clicks on it , (selects this object) i will open a directentry box(parented to aspect2d) which will take the input and update the text in the GUI object attached to render.

This terminal is just another node among many other nodes (which are not direct Gui objects but some geometry).

I understand the render part and directui parts well seperately. But i do not understand how i can use the directGui widgets attached to render, and how i interact with them.

When i said they have no effect i meant that Y dimension is ignored.
Since you mentioned, when does the Y-Cordinate have a meaning? (scratching my itch)

This is my second question: Assume that the node is placed at (5,0,0) which is 3 units right of the screen , how can i navigate to it. For example, when i load a model and setPos to (5,0,0), i move the mouse to my right holding the left click. But when the moment i add a DirectGui element to render, i tend to loose this functionality.The mouse stays where it is.

Thanks, for your patient replies.

OK, if you have a 2-D object under render, using the “picking” method is a fine way to interact with it. All you’ll get back is the fact that the user picked the object; you can then respond to this event by creating (or showing) the appropriate DirectGui objects under aspect2d, which will be fully interactive.

Note that the only thing your 2-D object under render is useful for is displaying text, and being picked on. For this reason, you might consider using a plain TextNode to generate the text, instead of a DirectGui object; the TextNode is more general and doesn’t make any assumptions that it will be parented under a 2-D scene graph. Also, for the purposes of picking, you will probably just want to make the background polygon pickable, not the text itself, since it is much faster (500 times faster) to check for picking on one large polygon than 500 smaller ones.

The Y coordinate is always in effect, but under render2d it just controls the depth of the text below or above the screen glass. Since the depth buffer is turned off for render2d by default, when two 2-D objects overlap, the one drawn last–normally, the one to the far right in the scene graph–is the one that ends up on top.

However, there might be times when you turn on the use of the depth buffer under render2d; in that case, when two 2-D objects overlap, the one with the smaller Y value will be drawn on top. This is the way the normal 3-D world works.

Also, whether or not you enable the depth buffer, if you set the Y value to very large or very small values (> 1000 or < -1000), it will get clipped behind the far plane or near plane.

Ah, I begin to understand. When you say “mouse”, you are referring to the point of view, am I right? Yes, for the 3-D scene, you can use the mouse to move your point-of-view over to the right to see any objects that might have been placed offscreen to the right. But you can’t do this for the 2-D scene–the coordinate frame is fixed to the glass. If something’s offscreen, it’s always offscreen.

This is the intention of the 2-D scene. The idea is that if you put something under render2d or aspect2d, you are putting it at a particular position on screen, and you normally don’t want the user to move things around willy-nilly. If you did want this, you could write code that would slide things around–for instance, you could do something like:


aspect2d.setPos(5, 0, 0)

to slide the whole screen over to the right. If you wanted this to be done in response to mouse commands, you’d have to write the mouse interaction code yourself (it’s not built into Panda by default).

On the other hand, you might consider using a DirectScrolledFrame, which is designed to do this sort of thing: then you can put your object inside the DirectScrolledFrame, and let the user bring it into view with the scroll bars when he wanted to see it.

David

For some rather complex GUI interaction with gui-elements that are rendered in the 3d space, the Doom 3 engine uses shaders which, while much more complex, would allow fully-interactive and complex GUI elements.

For example, players need to click on control panels in the game (and a mouse cursor is animated around the control panel during this), perhaps more interestingly, all of the standard HUD elements are driven by this shader as well.

Thanks for the clarification david. Textnode really made my work a lot easier.
Sorry, for delay in posting the reply.

Hamled, thanks for the inputs.

How do i get the background polygon of a text node?

I have looked at the documentation and tried adding the TextNode and NodePath of the text node to the mousePicker. But those approaches are not allowing me to pick a TextNode(It returns None).

Hmm, yes. Strictly speaking, a TextNode has no geometry, so you can’t pick it.

There are two possible workarounds.

(1) Create your own card to go behind the TextNode, using e.g. CardMaker. You should be able to say cardMaker.setFrame(textNode.getFrameActual()) to set the card to be the same dimensions as the text’s frame. Then you will need to either offset the text a few inches in front of the card to prevent Z-fighting, or explicitly decal the text onto the card, with something like this:

card = NodePath(cardMaker.generate())
tnp = card.attachNewNode(textNode)
card.setEffect(DecalEffect.make())

(2) Instead of parenting the TextNode directly to the scene, parent the node returned by textNode.generate() instead. This will be a static node that contains the polygons that render the text. If the text changes in the future, it won’t automatically update the geometry in this node; you will have to replace this node with the new result of textNode.generate(). But this node will be 100% pickable. In particular, if you have specified textNode.setCardDecal(1), then the first child of the node should be the card geometry.

David

Thanks for the reply david.I used method 2, since that seemed easy.

Btw, why do i need the cardgeometry, if i use this method? Does it mean that , the properties like getBounds etc of the card geometry are the bounds of the pickable object?

I have also added this in the docs, so that others can find it when needed.

You only need to isolate the card geometry if you want to make just the card pickable (instead of all of the poygons of the text) as an optimization.

David