One and one makes two!

So I’ve been recovering from the UI, fixing stuff like scissor rectangles and streamlining the setting of viewports and render targets. Since we need the render code to be as fast as humanly possible, I’ve been fiddling a bit trying to eliminate unnecessary state switches. Anyways…

We’ve had a small problem with using the physics for picking in the level editor. So I thought, hey! Why not adding per-pixel picking by rendering IDs for each entity to a buffer. This gives us a very nice projected representation of our scene, so we could just pick the pixel at the mouse position and voila, we have our entity! The only thing is that the render system isn’t and shouldn’t be dependent on the application system. So we need to be able to pick a game entity by clicking in screen-space, but we only actually have access to graphics stuff when rendering. What I did was to add a picking integer to the model entity, which is simply a generic identifier which we will use for picking. Instead of directly associating the game entity with the model entity, we instead use a generic identifier.

Note that we may want to use screen-space picking for other things than just the level editor, such as RTS selection, shooting in FPS or whatever. The only downside is that we must render everything again. We could just add this to our deferred rendering path, but we may also want to disable this feature to improve performance for games which doesn’t need pixel-perfect picking.

You may want to know what the title is all about. Well, I’ve also made it so that the content browser and level editor can communicate with each other. This means we can be in the content browser and edit stuff, save it and it will be immediately updated in the level editor. This is beautiful for many purposes, because an artist can sit in the content browser, fiddle around with their assets, and see how it would look in the level editor on the fly.

I’m trying to think of some image to put here just to show you how this works, but this week is highly functional, but not so much graphics related.

Ok, well, maybe that’s not entirely true…

While also implementing per-pixel picking, I’ve also done some work regarding the limitation of window size. I’ve made it so that we can re-size the entire Nebula context, and make every render target and render plugin get updated with the new screen size. This means we can have a variable-size window and render space, without losing quality or getting weird-looking aliasing artifacts. It’s also important for the render modules to get information about screen re-sizing, the UI for example needs the new dimension of the screen to properly scale and map mouse positions. The only downside to the re-sizing is that it of course costs a lot because every single render target needs to be destroyed and recreated.

An alternative to re-sizing the render targets could be to always render to a big render target, and then simply change the camera matrix to just view a portion of the entire frame. This might be an alternative, but since we couldn’t change the resolution in real-time before, I figured we might want this feature anyways.

I also realized I made a slight boo-boo with the bloom post effect, so that has been resolved and looks much better (like Vaseline on glass).

If that wasn’t enough, I also took the time to restore the old FX system in Nebula. It worked, sorta, the only problem it had was that it didn’t really respect the render-application thread border in any way. So I thought I could fix it so that it wouldn’t randomly crash. So now we can spawn fire’n’forget effects like camera shakes, camera animation tracks and time-limited graphics entities. Sadly, I’m too lazy to show you any pictures…

 

// Gustav

UI

This might sound like the most boring title of a post ever created in the history of the human species. Fortunately, I’m not only going to talk about UI, but I will start off by telling you that I’ve spend the last two days integrating libRocket (http://librocket.com/) into Nebula. Sweet stuff, really simple and easy-to-use library for creating good-looking dynamical UIs. That’s the UI part. Now comes the rage.

I can’t for the sake of my sanity understand what went through the heads of the developers of DirectX 10 and 11 when they thought it would be a good idea to have to manually link a specific vertex layout with a specific shader. Granted the same ‘signature’ can be reused in many other places, it’s still a retarded way of solving the problem. Now you may ask, what does this have to do with UI? Well, let me paint you the whole picture…

In Nebula, we load meshes dynamically (as I imagine every engine does it), which means we don’t always know what vertex components lie in the mesh. Additionally, we can use a mesh to be rendered with any given shader (as long as we’re not attempting something like skinning a mesh which has no blend weights). What this means is that we need for a mesh, a vertex declaration (which is some internal object that keeps track of inputs to the vertex shader). The vertex declaration is used by taking the bytecode of the compiled shader (intuitive!) and pairing it with the vertex declaration structure. The following code might give you an idea…

 

ID3D11Device* device = D3D11RenderDevice::Instance()->GetDirect3DDevice();
HRESULT hr;

// gets the active shader, will only succeed if there is no pre-effect (that is, will only work for post-effects)
Ptr<CoreGraphics::ShaderInstance> instance = ShaderServer::Instance()->GetActiveShaderInstance();
Ptr<CoreGraphics::ShaderVariation> variation = instance->GetActiveVariation();
ID3DX11EffectTechnique* technique = variation->GetD3D11Techinque();
ID3DX11EffectPass* pass = technique->GetPassByIndex(0);

D3DX11_PASS_DESC desc;
pass->GetDesc(&desc);

// this must succeed!
hr = device->CreateInputLayout(decl, compIndex, desc.pIAInputSignature, desc.IAInputSignatureSize, &this->d3d11VertexDeclaration);

 

In return we get a D3D11InputLayout, which we need when setting up the Input Assembler before we render. Doesn’t seem too bad does it? Beautiful. It literally means that I, for each combination of a mesh and shader, must create a new vertex declaration if there exists none, store it somewhere so that I can find it again (which is far from trivial), and then fetch it when I need it. The idea as far as I’ve understood it, which amazingly is also supported by a huge group of developers out there is that this allows for a pre-render initialization of the input declaration, which is then supposed to easen the vertex-buffer-to-vertex-shader linkage. Well, OK, fine. I can buy the argument that we can achieve a high level of optimization if we do this, maybe. Although I seriously doubt the bottleneck in earlier versions of DirectX (like 9 for example) was that the linkage between a linear VBO and a static vertex program was too slow. I can of course be wrong.

It shames me how I’ve solved this. I’m going to show you anyways however, just to give you a hernia.

 

this->d3d11DeviceContext->IASetInputLayout(vl->GetD3D11VertexDeclaration());

 

Gets called from when we set a vertex layout in the RenderDevice. Good enough, but watch this…

 

ID3D11InputLayout*
D3D11VertexLayout::GetD3D11VertexDeclaration()
{
// ugly, but hey, we need it!
CreateVertexLayout();
n_assert(0 != this->d3d11VertexDeclaration);
return this->d3d11VertexDeclaration;
}

 

The CreateVertexLayout function was the first one in the list. It also has a safeguard that prevents it from running if the Nebula vertex layout object has a DirectX 11 vertex declaration setup. But this literally means that we ‘test’ if there is a vertex layout before rendering. EACH AND EVERY TIME. Since a vertex layout has NOTHING to do with the shader in any other aspect than input to the vertex shader, this feels like the most forced limitation and cumbersome solution I’ve come across. It also means that I have to make sure the correct shader is set in the shader server, just so that vertex declarations will always correctly match. Remember that this is a getter-function which actually changes an internal variable. Ugh…

But wait, there is more! One would maybe perhaps think that DirectX 11 would tell you something if you try to, in the Input Assembler, combine some random vertex declaration with an incompatible shader. The only thing you will get is that the matching ‘segment’ of the vertex declaration works, the rest is just random data. This is how we get back to the UI part again. You see, I had a shader for the UI which should take three components. Here is the shader:

 

//——————————————————————————
/**
*/
void
vsMain(float4 position : POSITION,
float2 uv : TEXCOORD,
float4 color : COLOR,
out float4 Position : SV_POSITION,
out float2 UV : TEXCOORD,
out float4 Color : COLOR)
{
Position = mul(position, ModelViewProjection);
Color = color;
UV = uv;
}

//——————————————————————————
/**
*/
void
psMain(in float4 Position : SV_POSITION,
in float2 UV : TEXCOORD,
in float4 Color : COLOR,
out float4 FinalColor : SV_TARGET0)
{
FinalColor = Texture.Sample(TextureSampler, UV) * Color;
}

 

Simple. Well, what happened was that I forgot to set the global active shader when rendering the UI. This meant that my vertex layout for my UI didn’t get to link to the actual ui shader. Instead it defaulted back to the static shader (a default which I’ve implemented to avoid crashes when moving from a skinned to a static mesh), which in turn meant that my color component was cut off. No warning, no nothing, just a silent error, and several hours of searching and pulling my hair just to find out that the underlying system is <insert another lovely word here>. This method could be used if one only had a hard-coded set of shaders, and always knew which shaders should be applied on each mesh, but for a bigger scale application with a content pipeline, this just hurts. Physically.

Anyways, here is a picture of the result:

rocket

We should really consider moving on to OpenGL… The only problem is that the FX system is amazingly handy.

 

// Gustav

NIDL files everywhere!

Everybody that actually worked with N3 has probably stumbled over NIDL files. They are basically XML files that are compiled to c++ code via the idl compiler and then included in the project. They are used for example for defining the messages between entities/properties and for defining new scripting commands.

One of our age old problem when creating a level editor tool was the use of properties and attributes in the project. If the editor wants to be able to display information about properties and allow editing of attributes, it has to be linked to the actual project in some way since all that information is defined only in the code. At first we had the idea to turn everything into a shared library and use a simple launcher that will load the games shared library and then run it. That would allow the level editor to actually just load in the specific game’s library and add the actual properties to the project. While that would definitely be awesome we decided against that for the time being since we don’t have enough time.

Our much simpler solution is to have the level editor only use very simple entities with graphics and physics (for picking) and just use generic editor widgets for all attributes used by the entity. The drawback with this option is that it’s not possible to see the effect of most attributes live, but at least it is possible to edit, save and batch them to the level database.
However, this does not solve the problem of the editor not knowing about what attributes exist and are used by which entity class. Now this is where the NIDL files come into play again. I extended the idl compiler to support new entries for attributes and properties and even the information about what attributes are used by which property. Those NIDL files can then be used by the level editor to display and edit unknown attributes and properties, additionally the idl compiler will generate code that automatically defines and declares all attributes and even registers them in the properties automatically so that they don’t need to be defined in the code as well, thus avoiding the risk for them being out of sync.

Skip to toolbar