Conditional rendering, best practice? (SOLVED)

Hiya! I’m making a 3d app that doesn’t need to redraw the scene every frame. Right now, I have conditional rendering of a 3d predicate. Otherwise, I just clear the render and call render.draw().

This seems to work to swap the buffers (no jittering of last frames on android) but I’m curious what the best practice would be. Empty draw() call isn’t mentioned in the documentation for that function, so I’m not sure what it’s doing…

edit: I’m adding GUI now and realizing this might need to be a lot more complicated. I wonder if drawing the 3d view to an fbo is the best option, in order to reliably render the GUI and text on top of that…

Namely, setting the view/proj matrices loses the prerendered frame, but is necessary in order to draw the GUI in the right position… so I’ll have to either use an FBO or write custom UI code, maybe? Guessing.

I realize this might all still be WIP in the engine, or not possible to access as low-level as I want.

You are free to use FBOs, we call them render targets (and here). But you don’t need them to always get the GUI on top, in this case you would only need them if you wanted to not draw the 3d-scene, but draw dynamic GUI on top of course. Also for postfx and the like obviously. We always swap the buffers, so you need to make sure to at least draw two identical frames before stopping to draw. The render script is quite flexible, it’s more or less OpenGL, but missing some functionality. The drawing is based on material-tags and predicates, but it seems you already got passed that. :slight_smile: It’s a quite simple and open model.

3 Likes

Thanks for the response – I agree, this feels very simple and like working directly with OpenGL in a good way. :slight_smile: I managed to render my 3D scene to a render target, and then render that to a screen quad (-1 to 1 coordinates), but I still can’t seem to overlay the builtin UI on top. Text shows, with black backgrounds, and other GUI nodes don’t show at all. I tried moving the Z-order of the GUI game object in the main.collection, to no avail… I was seeing GUI nodes before, but I centered some objects in the collection and somehow it stopped working.

My render script is like this… note, I will probably try to use a screen quad in 0-1 and set the scale of the object to the window dimensions, in order to avoid having to set two ortho matrices here…

function init(self)
  self.view_pred = render.predicate({"3d"})
  self.screen_pred = render.predicate({"screen"})

  self.gui_pred = render.predicate({"gui"})
  self.text_pred = render.predicate({"text"})

  ...
  
  -- Set up render target
  self.view_color_params = {
     format = render.FORMAT_RGBA,
     width = render.get_window_width(),
     height = render.get_window_height(),
     min_filter = render.FILTER_LINEAR,
     mag_filter = render.FILTER_LINEAR,
     u_wrap = render.WRAP_CLAMP_TO_EDGE,
     v_wrap = render.WRAP_CLAMP_TO_EDGE }
  self.view_depth_params = {
     format = render.FORMAT_DEPTH,
     width = render.get_window_width(),
     height = render.get_window_height(),
     u_wrap = render.WRAP_CLAMP_TO_EDGE,
     v_wrap = render.WRAP_CLAMP_TO_EDGE }
  self.view_target = render.render_target("view", {
    [render.BUFFER_COLOR_BIT] = self.view_color_params,
    [render.BUFFER_DEPTH_BIT] = self.view_depth_params })
end

function update(self, dt)
  if self.redraw_needed then
    self.redraw_needed = false

    -- draw 3D scene onto the view render target
    render.enable_render_target(self.view_target)

    -- setup viewport and clear the texture
    render.set_viewport(0, 0, render.get_window_width(), render.get_window_height())
    render.clear({[render.BUFFER_COLOR_BIT] = vmath.vector4(0.35),
                  [render.BUFFER_DEPTH_BIT] = 1})

    -- setup state (we need to enable depth testing for 3D stuff)
    render.enable_state(render.STATE_DEPTH_TEST)
    render.set_depth_mask(true)

    -- set matrices
    render.set_view(self.view_mtx)
    render.set_projection(self.proj_mtx)

    -- draw 3d predicate
    render.draw(self.view_pred)
    render.disable_render_target(self.view_target)
  end

  -- setup sysfbo viewport and clear screen
  render.set_viewport(0, 0, render.get_window_width(), render.get_window_height())
  render.clear({[render.BUFFER_COLOR_BIT] = vmath.vector4(0.4),
                [render.BUFFER_DEPTH_BIT] = 1})

  -- enable orthographic rendering of screenquad into full window viewport
  render.set_view(vmath.matrix4())
  render.set_projection( vmath.matrix4_orthographic( -1, 1, -1, 1, -1, 1 ) )

  -- draw screen quad to sysfbo
  render.enable_texture(0, self.view_target, render.BUFFER_COLOR_BIT)
  render.draw(self.screen_pred)
  render.disable_texture(0)

  render.set_projection(vmath.matrix4_orthographic(0, render.get_window_width(), 0, render.get_window_height(), -1, 1))

  -- try to draw ui and text
  render.enable_state(render.STATE_STENCIL_TEST)
  render.draw(self.gui_pred)
  render.draw(self.text_pred)
  render.disable_state(render.STATE_STENCIL_TEST)

  -- render.draw_debug2d()
end

Is there something simple I’m doing wrong?

edit: Okay, so disabling depth test allows the gui nodes to render, but then my 3D scene texture is shredded for some reason. With depth testing left on, it works fine, but all I can see is the text – I’m okay with that, I can render my own GUI shapes. But now I need to solve the black text boundaries problem… wants a certain blend mode, I’m guessing?

Sorry for asking probably obvious questions, I’ll try to read the manual more closely.

Do you mind posting some screenshots? Try to turn off the depth test before drawing self.screen_pred:

render.disable_state(render.STATE_DEPTH_TEST)

Then enable blending before drawing self.gui_pred and self.text_pred (actually I think we currently draw the text using the “gui” tag, you can dig into the font materials to find out).

render.enable_state(render.STATE_BLEND)

We try to interfere with the GPU state as little as possible outside of the render script, there is really no reset of anything. So don’t forget to disable and enable the states as needed, i.e. disabling blending for the 3d if you don’t want that. I should also mention that we always sort back to front currently, so there is no real gain in depth-testing within the same render.draw, but it can of course be useful across several render.draw calls.

1 Like

That did it, thank you. Here’s before, without disabling depth before rendering my self.screen_pred, but disabling it before gui and text:

And here’s after, though I had to:

  • disable render.STATE_DEPTH_TEST before rendering to quad
  • disable render.STATE_CULL_FACE so text is visible (must be wound backwards)
  • enable render.STATE_BLEND for text rendering
  • enabling render.STATE_STENCIL_TEST doesn’t seem to make a difference in this example, but it’s in the default render script so I assume it’s for something like opacity on GUI node textures.

That all makes sense now. Thanks for pointing me in the right direction!

4 Likes

Good call with the text polys, seems to be a bug! The stencil test is only used for GUI clipping.