3D UI transformation matrix

Started by
4 comments, last by luorax 9 years, 7 months ago

Hello there community!

I'm trying to extend my 2D UI to the third dimension, to allow 3D components. When I first played Crysis 3 I really liked the 3D hud and I'd like to be able to create similar UI components (for those who're not familiar with Crysis 3, here is a screenshot - I'm talking about the map and weapon components).

This is how I'm rendering my UI right now:


GLfloat width=(GLfloat) CEngine::getInstance().getWindow()->getWidth();
GLfloat height=(GLfloat) CEngine::getInstance().getWindow()->getHeight();
glm::mat4 viewProj=glm::ortho(0.0f,width,0.0f,height,2.0f*width,0.0f);

////////////////////////////////////////////////////
//  Render all the visible UI elements
for (auto it=s_uiElements.begin();it!=s_uiElements.end();it++)
{
    CUIElement* element=*it;

    if (element->m_visible)
    {
        element->m_ubo->bindBase(CShader::UNIFORM_BINDPOINT_UI);
        element->m_transform=viewProj*element->m_model;
        element->uploadData();
        element->renderThis();
    }
}

A simple perspective projection, nothing fancy.

This is how I'm trying to set up the perspective projection:


glm::mat4 projection=glm::perspective(glm::radians(90.0f),width/height,0.0f,width);
glm::mat4 view=glm::lookAt(glm::vec3(width*0.5f,height*0.5f,0.0f),glm::vec3(width*0.5f,height*0.5f,-1.0f),glm::vec3(0.0f,1.0f,0.0f));
glm::mat4 viewProj=projection*view;

But it just doesn't work.

Could someone tell me what I'm doing wrong, and how I could approach this? I just can't figure it out on my own.

P.s: as for the model matrices and vertex data: they're rendered as quads ((0,0),(0,1),(1,0),(1,1)) and the model matrix takes them into the appropriate window position ((0,0)-(width,height)) and size.

[EDIT]:

For clarification: I have all the vertex data, model matrix, and all the like set up properly. I've been able to render 2D elements just fine for months, but I want to move to 3D now. All I need is a proper projection/view+projection matrix, that I could use to take the UI element's Y rotation and give it some depth.

My vertex data is set up such that each vertex falls into the vec2(0,0)-vec2(window_width,window_height) range, and the Z component is 0 by default, but it can be changed with rotations.

I have recently added support for various fill (normal / radial) and color (constant / gradient / radial gradient) methods, and I happen to have a screenshot of what I've got right now: [link]

Advertisement

Off the top of my head, there's probably a could of ways you could do this:

  • Set your WIdgets transform to be your camera's position, then offset it a bit and rotate to get it how you want. Probably want to turn off depth filtering/writing as well.

or

  • Render all your widgets to separate texture (all rotated and such just using normal matrix math), then draw the UI as full screen quad over your scene before you present the frame.

The only real difference is one uses your camera and one has no camera and all your widgets are rendered around the origin and then rendered a final time over the scene. There might be some even simpler method, but these are just some ideas off the top of my head.

I've edited my post, I didn't word it properly. I can render things in 2D, that's a no-brainer, my problem is with creating a proper perspective projection matrix. The one I have in the second code tag does not work. I've been working on other stuff all day, might give it another go later, propably in the evening or so.

Sounds like you have your widgets in currently in screenspace. If you want them 3D you probably want them in world space (again, just out in front of your camera), rotate them there, and then multiply them by your ViewProjection matrix. Your view matrix doesn't make much sense to me, you're treating it like you're still in screen space when you're not.

If this is your first foray into 3D graphics you may want to read up on some linear algebra/matrix transformation tutorials (I don't know any great ones off the top of my head, maybe someone has a good suggestion and can chime in). Or am I misunderstanding your issue?

No, you got it right. And no, I'm not new to graphics programming either, it's just I have this specific problem which I'd like to solve in this specific way, but sadly, it doesn't seem to work out as I imagined.

What I was trying to do in the code above is create a view matrix at the center of the window and look at the elements from there, but I realised it myself that it won't work like that and now I'm in the process of rethinking the whole problem.

Doing the UI in world space is what I've been thinking of,too. My problem with that though is that I'm still not sure what kind of projection matrix I should use (propably a custom one, and not the projection matrix used by the 'camera', so changing the camera would not affect the UI - but I don't know if a fov of 90 degrees is correct for it) and that I'd lose my ability to position my UI elements in window space, which is something I really liked and would like to keep, if possible, because that eases my work a lot. Or maybe I would, and maybe I'm just not understanding this more advanced projection matrix, that incorporates things like aspect ratio and field of view - the one we learned about at school is much simpler. In all honesty, I haven't taken the time to investigate closely the more complex perspective matrix, I just relied on glm creating it for me, and it looks like now is the time when I see why it was a mistake.

I'm off for today, but I think I'm gonna have to do some major changes to get this thing done, much more than I've anticipated.

Okay, so I'm setting up my projection matrix like this now (and no view matrix, it's not needed):


glm::mat4 projection=glm::perspective(glm::radians(90.0f),1.0f,0.0f,width); //aspect ratio is 1.0, no correction needed

This allows me to use positions and sizes from the [-1,1] interval. a.k.a. directly mapping my UI components to the screen. It's not as nice as using window coordinates, but it has an even better advantage: it scales with window size / resolution. Using window coordinates is bad because I noticed that if I played around with my window's size, things would randomly become visible/invisible as they go out of screen - this solution, however, does not suffer from that problem.

I still need to fix a few things (text rendering, image borders do not show up just yet, mouse clicking on buttons), but I think I'll be good, once I redo my UI using the new system.

This topic is closed to new replies.

Advertisement