Aeva / m.grl

Midnight Graphics & Recreation Library
http://mgrl.midnightsisters.org
GNU Lesser General Public License v3.0
44 stars 3 forks source link

Refactoring Object Picking System #237

Closed Aeva closed 7 years ago

Aeva commented 8 years ago

This issue is part of #232, and also relates to #192.

This encompasses the following tasks:

Aeva commented 8 years ago

It occurs to me that there is another benefit to using indirect rendering for picking - we don't need to re-render the scene for every mouse event.

Instead, rendering the picking buffers would only happen upon a mouse event if the current buffers are out of date. We could have the picking node be frame limited at 15 or 30hz, and only render if some dirty flag is set.

The dirty flag would be set by the mouse event handlers, and is unset by the picking node when the event queue is empty.

Mouse events then could be processed out of phase with the render loop, however a mouse event triggers the dirty flag, then processing the events should be blocked until after the buffers are redrawn.

The sampling frequency should be exposed as a picking option.

Aeva commented 8 years ago

Picking RenderNode is generating bad source code:

// BEGIN GENERATED GRAPH RENDERING CODE

this.prog.vars[mgrl_model_local_min] = [object Float32Array];
this.prog.vars[mgrl_model_local_size] = 4,4,0.48876953125;
this.prog.attrs['position'].enabled = true;
this.prog.vars['mgrl_model_local_min'] = [object Float32Array];

Note that it is generating arrays wrong in two different ways.

Aeva commented 8 years ago

an even better idea than running the picking passes at a lower frame rate and lower resolution is to be more like a tiling renderer, and only render the pixel under the mouse

Aeva commented 8 years ago

Rearranged some of the tasks above. I removed the MRT one since I'm not sure there is as much benefit to it at the moment. I think the tiling thing will be a much bigger improvement, such that it might not be necessary to also add in MRT stuff.

The tiling stuff might appropriately go into its own ticket later too, though it should not be hard to implement.

Aeva commented 8 years ago

Up next is to do the tiling optimization and throw together a new way to do composited picking coordinates.

Composited picking unfortunately doesn't play nicely if I'm only rendering the area directly under the mouse for picking. Two work-arounds come to mind so far, ordered in preference:

I think I'm going to go with the picking function, since this is kind of a niche feature.

UPDATE I went with the picking function, and it works better than the original implementation :D

Aeva commented 8 years ago

Grep tells us that the following demos need to be ported:

Aeva commented 8 years ago

bezier_pick demo is converted to the new API, but the demo is now broken.

Aeva commented 8 years ago

Picking pass now only renders into a small tile! 8x8 seems to be the minimum it wants to do, it works fine with that.

The pick coordinates seem to be slightly wrong though, but that should be easy enough to fix.

Performance-wise seems to be marginally better? Enabling move events in the location_picking demo seems to yield 20-30 fps rather than 15ish(??). Last figure is from memory, but I can't imagine this hurting anything at least.

I guess the other thing to try is probably going to be to frame limit when the picking pass can run (not the rendenode but the outter logic itself, because otherwise we'll just get cached results from previous passes). Or just rate limit move events and accept all clicky events.

Aeva commented 8 years ago

Updated one of the bezier demos to use the layers mechanism, but it doesn't quite work yet. The reason for this is probably because the picking IDs are only being set for static objects. The demo uses "floor node", which is only able to run in the dynamic path at the moment.

What I should do here is first update the picking system so that the color ids are generated correctly for all objects etc, and then probably re-work the floor node so that it can generate IR and run static.

Aeva commented 7 years ago

There were some mystery changes on my computer which I've checked in to their own branch ("loose_end") and pushed up here. You can see them here 12c1e8d8bafc1d6. At the time of writing, I don't remember what I was doing with them, ~but it broke the build.~

Correction: The index demo is broken, but that is consistent with the fast_graph branch. The distorted picking demo works fine.

Aeva commented 7 years ago

Digging into the "loose_end" branch a bit, it looks like I was trying to do the following:

  1. updated bezier_pick demo to use a "layer" based approach to allow multiple picking graphs
  2. added some sort of "__all_drawables" array, which was probably intended to remedy the problem of only being able pick static objects

I'm pretty sure the layers functionality already exists in pick_nouveau and I probably just forgot to check in the changes to the demo before attempting to monkey around with other functionality.

So my guess is, the fact that nothing happens when you click on stuff in the bezier_pick demo is likely a problem with the __all_drawables thing, and not the other stuff.

Aeva commented 7 years ago

Further poking around confirms:

  1. can click to select the control points
  2. picking layer then changes to the "drag" layer
  3. picking layer reverts to "select mode" on mouse up

So, most of the machinery here is working right, and the problem is probably in the rendering function for 'drag mode'.

Aeva commented 7 years ago

Commit bcbca69b665a363e9460a03071d3a95d71b769d3 adds the sourceURL directive to generated code. This should help a lot in debugging the loose_end branch.

Aeva commented 7 years ago

It looks like the secondary picking shader should be getting the right object_id assigned now for the floor, and the draw calls are being hit correctly for that. Sticking a break point in please.picking.__etc.picking_pass though says its only reading [0,0,0,0] from the picking pass :/ so something isn't working right still.

Aeva commented 7 years ago

I'm running out of ideas, so I think the best course of action is to solve an adjacent problem and hope it fixes this one too:

Currently there is just one rendernode "singleton" for the picking system. This is a problem, because it requires hotswapping the GraphNode for it, triggering a recompile event for the picking pass. A better solution would be to just generate a RenderNode for each tracked graph node.

Commit 30bca546eef5322071bfe6c115f02282d2b888c2 adds this functionality, but it does not solve my problem D:

Aeva commented 7 years ago

As best I can tell, the following is true now:

The space expected to be occupied by the FloorNode objects in the picking graph is always [0, 0, 0, 0] somehow.

edit AAAAAH ok found a pattern here - there is a FloorNode instance in both graphs, and in both graphs the color picked is black.

Other things to note:

wijnen commented 7 years ago

The idea of picking is that you render the scene with a special shader offscreen, and then read a pixel from the render result, right? I'm probably missing something, but it seems that the easiest way to debug this is to draw the result of the picking render on screen?

Aeva commented 7 years ago

Basically, yeah. I'm adapting the old object selection system over to use the fancy new rendering infrastructure that I've been working on for the last half year.

So with regards to drawing out the buffer somewhere - I could do that, but I can get the same information that would give me by reading out the color picked, which is relatively easy to do. But by doing essentially that, I know that it is working for some objects, but not others in this case.

So in particular, consider this generated picking pass: https://gist.github.com/Aeva/8bc47097c4d7c7e3381c5d6549023953

Everything from lines 29 through 221 renders correctly.

Then on lines 230 and 231, a single "legacy renderable" (the floor node) should be drawn. The bind and draw methods DO get called, and the old drawing infrastructure for it actually does execute, but that area of the buffer ends up still being just the clear color.

Aeva commented 7 years ago

Ok, I fixed that blocker finally, though I'm not sure why it works now. I removed the tiling optimization for picking, so it renders to a normal buffer now, and as a result, the FloorNode in the bezier demo is now selectable.

I also updated the FloorNode to use the new rendering path, really only for ease of debugging, but everything should use that eventually.

I've not yet looked into why yet, but the location picking results for the floor node are very wrong - I suspect it relates to the location picking stuff being off for the location_picking demo, too. Object selection seems to be on point, however.

Also: I merged loose_end into pick_nouveau and deleted loose_end.

Aeva commented 7 years ago

The value of loc_color on this line is always [1, 0, 0, 255] in the bezier curve demo as is, when you try to drag around a marker regardless of which marker. Otherwise, it seems the demo is working as expected now.

In the location_picking demo the value of loc_color is constant for a given object, but different for different objects. It is somewhat consistent spatially, so the demo is somewhat more functional. If the demo were to use a FloorNode for location picking, it would likely behave similarly to the bezier curve demo.

For the bezier_curve demo, the output of gl.readPixels for the entire buffer reveals it to be a consistent color. Also, the inputs look fine (vbo.stats.min and vbo.stats.size appear to be specified correctly) and it looks to be in the correct mode renderer.shader.mgrl_select_mode = false.

From the behavior as is, it looks like it could be either that the local_position varying var is wrong, or mgrl_select_mode is actually true somehow, and its just a coincidence that the location picking demo seems approximately correct.

Hah, found it! The problem is caused by the caching mechanism in the compositor. The picking pass renders once for selection, writes to the buffer and caches it, and then the picking pass is rendered a second time, but the cached result is returned, thus the values are wrong for location picking. Oops!

Aeva commented 7 years ago

This issue is basically complete now, to recap from the checklist at the top of the page, the following needs to be done before this can be closed:

Aeva commented 7 years ago

The slow_bezier demo appears to have a regression (move a control point and you'll see it) - there will be lamps drawn at the origin that never move.

What is actually happening, is that the demo would normally set their visibility to false. The demo is unable to do this because the new rendering pathway doesn't support changing visibility yet. So, this is not a bug in the demo, but a missing feature in the new rendering pipeline.