problem with TextSprite

Oct 10, 2012 at 8:20 PM

i´m facing the following problem with TextSprite:

textsprites are always projected onto the 0-Z-plane of the world-space so i can position texts only correct onto the viewport-plane combined with the Camera2D. the same problem exists eg. for "unithints" flying over a model.

i tried to derive from TextSprite and implement my own Draw, that projects using vieport.project, but there seems to be some world/parent transformation that makes my trial very hard. using a newly created spritebatch in my derived class draws correctly, but drives the framerate into the ground.

is there a way to influence projection?


Oct 11, 2012 at 2:34 AM

Yes, this is a hard design decision to make when drawing 2D stuff over a 3D world.

Ideally, you can attach a TextSprite to a 3D model and that TextSprite will be projected to 2D space at the correct screen position. The problem become complicated if you try to build a 2D transform hierarchy using Group, and then attach that 2D Group to a 3D model. The transform hierarchy calculations just don't fit when part of the scene tree is 3D and the other part is 2D.

So I'm currently making Sprite/TextSprite to work only in 2D space, which is rendered using Camera2D. There is currently no GUI system in Nine, so I think the problem can be walkaround by leveraging whatever GUI system you are using.

I'll probably come up with better ideas to handle this when it's time to create the GUI system.

Oct 11, 2012 at 2:26 PM

i´ll give it a try to implement my own ui. is there a way to bundle similiar draw-calls to a separate pass (same as you do in your SpritePass)?

Oct 12, 2012 at 2:16 AM

I think you can completely seperate UI rendering from scene rendering while still able to attach the UI element to the scene tree. To do that:

1. Create an interface for your UI object like IUIElement

2. Create commonly used UI controls that implements IUIElement, like text block, button, etc.

3. Add this UI controls to the group

4. Create a SceneExtensions for UI rendering. Store your global UI rendering context using an attached property. Refer to the implementation of  Nine.Physics.SceneExtensions or Nine.Graphics.SceneExtensions

5. Retrieve you UI controls from the scene Tree. Again, refer to Nine.Physics.SceneExtensions.

6. Create an extension method like scene.DrawUI() to render all the UI elements. Manually call this method after calling scene.Draw().

This design decouples the graphics, UI, physics, audio, networking systems of the game.

Oct 15, 2012 at 8:49 PM
Edited Oct 15, 2012 at 8:49 PM

great - i implemented a minimalistic ui with a Text-Element and an Image-Element for my POC. it works as designed ;-)

for future a can see 2 potential problems with it:

1. there might be ui-elements that should be rendered behind normal scene (background-image, ...) so the ui-draw-call could have to be split up into two separate, selecting some ui-elements based on a ZOrder or similar

2. post-effects wouldn´t work on ui-elements

but for now it works ...


thank you

Oct 16, 2012 at 2:36 AM


For the 2 potential problems, it is possible to solve within the current framework, but they both require access to the internal drawing flow through the DrawingContext.Passes property.

A drawing context keeps track of a list of passes. When rendering, each pass is executed sequentially. Passes are sorted by order and dependency. For example, shadow map generation is a pass, a post processing effect is a pass, the rendering of 3D objects and 2D objects are 2 seperate passes. You can find all the built in passes inside Nine.Graphics.Drawing namespace.

The pass list is dynamic and changes according to the structure of the scene. If there is no visible shadow receivers in the current view, the shadow map pass is not even created. But once an object is tagged to use deferred lighting, a LightPrePass will be created and enabled for that frame.

So to render UI before post processing, create a UIPass, give it an order between MainPass and post processing pass, and then add the UIPass to the DrawingContext before DrawingContext.Draw.

To render background UI, draw that UIPass before MainPass. But I think the current MainPass implementation always clears the backbuffer, this behavior has to be changed a little bit.


Dec 15, 2012 at 1:43 AM
This discussion has been copied to a work item. Click here to go to the work item and continue the discussion.