Gui in 3d?

Hi!

Quick question hopefully with an easy answer: i’m making a game entirely out of GUI nodes, and I was wondering if it would be possible to render GUI nodes using a perspective camera. I guess I’d have to make some changes to the render script. Is this an impossible dream?

Basically I want to set my level select screen up so that each level is in a book that the player opens. The only thing i need to do is rotate the book cover when the player clicks on the book.

I might try doing it in 2D and cheating, but if i can just use a perspective camera, that would make things a lot easier.

You should be able to draw a custom GUI render predicate to a render target which shares a texture with a GO/sprite that can then be orientated around in 3D space.

Mm hm. Mm hm. I know what some of those words mean. I will have to investigate but i think i will just find another way of doing this, because i have no idea how to even start doing that.

Okay… another quick fix would be to render GUI behind GOs. That would be easy to change in the render script, right? just move the GUI render stuff up to the top.

Yes, that shouldn’t be a problem I think

Okay, I have to admit that i was actually hoping for some practical advice. I’ve got @ross.grams rendercam, but it’s not rendering sprites at all and 3D rotated gui nodes are rendered. I am looking at the rendercam script but i don’t understand any of it. I’ve also never dealt with materials before.

For now I will try using stencils, clipping and ingenuity to make this in 2D.

You should study each part one at a time, you will get it. Like how to use render targets would be good to play with. Here’s a sample

RenderTargetExampleWithFXAA.zip (1.0 MB)

Then another thing to learn how to do would be to render something to a render target texture resource that is also used by a sprite. It should be possible. :smiley:

1 Like

Like banksy said: if you learn how to cheat, you never have to learn anything else!!!

Here’s my solution using just two additional GUI nodes and 3 additional animations (compared to animating rotation.y of a single one gui node).

There’s still some stuff i need to fix:

  • I’d like to improve the easing.

  • I’d like to adjust the scale.y for each letter of the front cover individually, which will involve creating one letter per label. but that’s not hard

  • I’d like to not cheat a little bit: the scale.y of the triangles at the top and bottom of the cover continue to increase even once the Y rotation has passed 180 degrees. Ideally, I’d like to automatically do some maths that calculates the scale of those triangles according to the scale.x of the cover, but maths makes me sad especially when i have to calculate curves.

  • Code

      				--start the anims!
      			local halftime = 0.8
      			local bookdelay = 0.2
      			local height = 90 -- perspective
      			local textfade = 0.7 -- between 0,1. It's a divider.
      			local easing = gui.EASING_INOUTSINE
    
      			--whole node anim
      			gui.animate(v, "scale", 1, go.EASING_OUTCUBIC, 2)
      			gui.animate(v, "position", vmath.vector3(self.screenwidth/2, self.screenheight/2, 0), go.EASING_OUTCUBIC, 2, 0, stateup)
      			--book opening anim
      			gui.animate(gui.get_node("covertext1"), "color.w", 0, gui.EASING_INQUINT, halftime*textfade, bookdelay)
      			gui.animate(gui.get_node("cover1"), "scale.x", -0.3, easing, halftime, bookdelay)
      			gui.animate(gui.get_node("toptriangle1"), "scale.y", height, easing, halftime, bookdelay)
      			gui.animate(gui.get_node("bottomtriangle1"), "scale.y", height/2, easing, halftime, bookdelay)
    
  • vid:

1 Like

…basically, I need to know the function by which

if x = 1 then y = 0
if x = 0 then y = 1
if x = -1 then y = 0

and yes i know it’s related to SIN COS and TAN but I found maths class difficult (due to constant distractions by an amateur rapper called MC whitesnake who used to sit next to me)

Hmm, there’s a few questions that require long answers in this thread…

Render Predicate - This just means a group of things that get rendered together. If you open a material file, at the bottom it will have a tag set. Sprites and things have the “tile” tag, gui has the “gui” tag, etc.

In your render script init() you will see this:

self.tile_pred = render.predicate({"tile"})

…which defines a predicate of all things with a material with the “tile” tag. When you want to draw that stuff, in your render script, you do:

render.draw(self.tile_pred)

Drawing GUI in persective
Yeah, theoretically you could just move render.draw(self.gui_pred) up to where sprites are drawn (next to render.draw(self.tile_pred)), in your render script. I’ve never actually tried it though, so it may mess up. GUI nodes ignore their Z position…I’m not sure how that would work with a perspective camera. I would suggest using game objects and sprites or models instead, unless there’s a reason why you must use GUI. If all you’ll ever need is the book cover, faking it with two triangles is a good idea.


"Flipping" 0-1
(1 - x) is the function you’re looking for.
1 - 1 = 0
1 - 0 = 1

1 - 0.5 = 0.5
1 - 0.25 = 0.75
1 - 0.75 = 0.25, etc.

2 Likes

Hi Ross!

Thanks so much for your detailed answer. I realised after what Pkeod said that it would involve a lot more knowledge than I have right now; and I have so much other stuff I should learn before i get into rendering. And, as you said, faking it with triangles wasn’t too hard.

I didn’t fully explain the flipping thing, but I have now realised that what I need is something like math.cos(X*math.pi) in order to calculate the curve by which to scale the height of the triangles, as well as the height of the letters, which I will also distort according to their X position.

I do have just one more quick question: in my updated version, I animate the scale.x of the GUI node that works as the book cover, and then in my function update(self, dt) I set the height of the triangles using math.cos(scale.x*math.pi). But the thing is, that’s the only thing in my update function. and I’d like to know if I could eliminate the need for an update function by somehow only changing the height of the triangle during the animation.

My delicate little dilemma seems relevant to this thread.

I’d like to rotate a pie node on the z axis to be able to choose where set_fill_angle() starts. I also want to set the height smaller than its width:

Here I’ve got a box node with rotation 55 on the x axis, and the nested pie node is is rotated 36 degrees on the z axis. Nice!

This is how it comes out in game:
25

I’ve been playing around with the rendercam.render_script in the hope of being able to display it properly without luck.

Is it possible to render it properly OR is it possible to set the start point of a pie node without rotating it?

Edit: Yes, it’s possible to do this in 2D, using scaling rather than 3D rotation. Here the pie node is rotated around its z axis while the box node has an y scale of 0.6. Boom!

This is related to what I was asking about, but I don’t have enough knowledge on many of the topics that came up in order to solve that problem. Objects and gui elements are not automatically rendered in 3D in-game, even though they are rendered like that in the GUI.

I’d actually say it makes more sense to make the 3D cam/perspective cam (or whatever it is called) as the default camera. I can’t think of any use case where someone would want such a drastic difference between the editor view and the in-game view, or why that view would be the default.

It’s interesting that both of us ended up using faux-3D methods when the 3d option would have been so simple!

1 Like

How are you setting up the rendering of the GUI in the renderscript?

The wrong way, for sure! I was trying to copy the render code that renders 3D models and use it for GUI. Probably like trying to crochet with a sledgehammer.

I was just playing with render script stuff and decided to try this.

defold_ortho_gui

All you need to do is increase the depth that you’re rendering. Your projection near-Z and far-Z are probably -1 and 1, so if you rotate things at all, most of the geometry will be out of range, that’s why you only get a line. You’ll also probably want to enable the depth test, if you have different things rotated different ways and overlapping each other.

code snippet
-- The last two numbers in this line are the crucial bit:
self.gui_projection = vmath.matrix4_orthographic(0, self.win_w, 0, self.win_h, -200, 200)

render.set_viewport(0, 0, self.win_w, self.win_h)
render.set_view(IDENTITY_MATRIX)
render.set_projection(self.gui_projection)

render.clear({[render.BUFFER_DEPTH_BIT] = 1})
render.enable_state(render.STATE_DEPTH_TEST)

render.enable_state(render.STATE_STENCIL_TEST)
render.draw(self.gui_pred)

This is still orthographic of course. If you actually want perspective it would be a little bit more fiddly since you’d need to move the “camera” “closer” on the Z axis to actually see anything (or move all your GUI nodes far into the negative-Z).

[Edit] OK, you’ll want to clear the depth buffer too, or your GUI can get overlapped by your sprites. (fixed code snippet).

4 Likes

Blimey, this black magic might come in very handy. Thanks @ross.grams!

1 Like