How to draw a line in VR in HARFANG?

Question:

I am using HARFANG for a scientific visualization project in VR, with the Python API. I based my work on the tutorial given here: https://github.com/harfang3d/tutorials-hg2/blob/master/scene_vr.py

But there is one thing I can’t do 🙁
Is it possible to display vertices and lines in the VR view?

To do this in the render pipeline I figured out from the tutorials that the line vid = hg.GetSceneForwardPipelinePassViewId(passId, hg.SFPP_Opaque) would let me get the exact render pass into which I could inject my line draws.

However, I can’t get it to work in a VR code. The best I’ve been able to do so far is to desync the view of the two eyes…

Asked By: pyblek

||

Answers:

What happens here is that your views are overwritten by the drawing pass of your lines.
You have to figure out how BGFX works: it uses a (very simple) system of views, indexed by IDs going from 0 to 255.

As detailed in the manual :

Each call to a drawing function such as DrawLines or DrawModel is queued as multiple draw commands on the specified view. When Frame is called all views are processed in order, from the lowest to the highest id.

What you need to do is to increment the view id before using it for your specific drawing commands:

    vid = 0  # keep track of the next free view id
    passId = hg.SceneForwardPipelinePassViewId()

    # Prepare view-independent render data once
    vid, passId = hg.PrepareSceneForwardPipelineCommonRenderData(vid, scene, render_data, pipeline, res, passId)
    vr_eye_rect = hg.IntRect(0, 0, vr_state.width, vr_state.height)

    # Prepare the left eye render data then draw to its framebuffer
    vid, passId = hg.PrepareSceneForwardPipelineViewDependentRenderData(vid, left, scene, render_data, pipeline, res, passId)
    vid, passId = hg.SubmitSceneToForwardPipeline(vid, scene, vr_eye_rect, left, pipeline, render_data, res, vr_left_fb.GetHandle())

    # Prepare the right eye render data then draw to its framebuffer
    vid, passId = hg.PrepareSceneForwardPipelineViewDependentRenderData(vid, right, scene, render_data, pipeline, res, passId)
    vid, passId = hg.SubmitSceneToForwardPipeline(vid, scene, vr_eye_rect, right, pipeline, render_data, res, vr_right_fb.GetHandle())

    # Display lines:
    hg.SetViewFrameBuffer(vid, vr_left_fb.GetHandle())
    hg.SetViewRect(vid, 0, 0, vr_state.width, vr_state.height)
    hg.SetViewClear(vid, 0, 0, 1.0, 0)
    hg.SetViewTransform(vid, left.view, left.proj)
    draw_line(vid, hg.Vec3(-2, 0.5, 0), hg.Vec3(2, 0.5, 0), hg.Color.Red, hg.Color.Blue)
    
    vid += 1

    hg.SetViewFrameBuffer(vid, vr_right_fb.GetHandle())
    hg.SetViewRect(vid, 0, 0, vr_state.width, vr_state.height)
    hg.SetViewClear(vid, 0, 0, 1.0, 0)
    hg.SetViewTransform(vid, right.view, right.proj)
    draw_line(vid, hg.Vec3(-2, 0.5, 0), hg.Vec3(2, 0.5, 0), hg.Color.Red, hg.Color.Blue)

    vid += 1

And from here you can go on with the rest of the code snippet you mentioned

As told in the manual, the lines will be drawn after the scene (thanks to the view id being incremented), so you can either clear the DepthBuffer or keep it so that the lines will go through your objects.

Please also note that you have to increment the view id because you are doing custom rendering operations. Most of the time, the API will do it for you (as PrepareSceneForwardPipelineViewDependentRenderData or SubmitSceneToForwardPipeline for example)

Answered By: Oucema