Question Toggling Mesh Group Visibility During Session?

Thunder Chicken

Resident Lua Script Rabble-Rouser
Donator
Joined
Mar 22, 2008
Messages
5,845
Reaction score
5,509
Points
188
Location
Massachusetts
I am trying to toggle the visibility of a sail on my skiff during the session with a boolean flag, but without any luck. Here are the relevant bits of my code:

In clbk_setclasscaps I have a loaded mesh with handle hmesh and identify the mesh groups for the sail:

Code:
sail_meshgroup = {14,15}

I am toggling with a boolean sail_up. When true, the sail should be visible, when false, it should be invisible.

I have tried the following code in both clbk_prestep and clbk_visualcreated, but to no avail:

Code:
    --set sail
    
    for i = 1, #sail_meshgroup do

        ges = {}
    
        if sail_up == true then
        
            ges.flags = GRPEDIT.SETUSERFLAG
            ges.UsrFlag = 3
        
        elseif sail_up == false then
        
            ges.flags = GRPEDIT.SETUSERFLAG
            ges.UsrFlag = 1
        
        end
        
        oapi.edit_meshgroup(hmesh, sail_meshgroup[i], ges)
        
    end

end

I initialize the boolean, and the mesh will either be visible or invisible at the start of the simulation based on that initial status, but it won't toggle during the session when I change that boolean. I'm honestly just pattern matching code @Gondos pointed to me to that makes the passengers appear/disappear in the DG, but I'm not wholly understanding what I am missing.
 
I did some tests in the DG by toggling SCRAM visuals based on the cockpit light switch and the SCRAM lever does appear/disapper when I toggle it.
Where does your hmesh come from?
self:get_devmesh or oapi.load_meshglobal ?
 
UsrFlag bit fields (or FLAG entry in a group of a mesh file):
1733419841706.png

Usually it is either 0 (show) or 3 (hide mesh and shadows).
 
I did some tests in the DG by toggling SCRAM visuals based on the cockpit light switch and the SCRAM lever does appear/disapper when I toggle it.
Where does your hmesh come from?
self:get_devmesh or oapi.load_meshglobal ?
oapi.load_meshglobal in clbk_setclasscaps:

Code:
    hmesh = oapi.load_meshglobal('Skiff/Skiff')
    vi:add_mesh(hmesh)

EDIT: I tried this, but it still does not change the mesh group visibility:

Code:
function clbk_visualcreated(vis, refcount)

    hdevmesh = vi:get_devmesh(vis,0)

    --set sail
    
    for i = 1, #sail_meshgroup do

        ges = {}
    
        if sail_up == true then
        
            ges.flags = GRPEDIT.SETUSERFLAG
            ges.UsrFlag = 3
        
        elseif sail_up == false then
        
            ges.flags = GRPEDIT.SETUSERFLAG
            ges.UsrFlag = 0
        
        end
        
        oapi.edit_meshgroup(hdevmesh, sail_meshgroup[i], ges)
        
    end

end
 
Last edited:
oapi.load_meshglobal in clbk_setclasscaps:

Code:
    hmesh = oapi.load_meshglobal('Skiff/Skiff')
    vi:add_mesh(hmesh)
You must use the one you get from get_devmesh.
From the doc :
* Handles for the individual mesh copies can be obtained within the
* VESSEL2::clbkVisualCreated() callback function, using the
* VESSEL::GetMesh() method. Vessels should only modify their individual
* meshes, never the global template, since the latter is shared across all vessel instances.
* \note For external graphics clients, the Orbiter core forwards the mesh data
* to the client for conversion to a device-specific format. The mesh template
* referred to by the handle returned by oapiLoadMeshGlobal is then no longer
* used, so any changes made to it will be ignored.
 
You must use the one you get from get_devmesh.
From the doc :
I edited my previous post just as you sent this. I did try that as well, no change in mesh visibility:

 
Since we're on the subject, a rookie question, what is the difference between hmesh obtained from oapi.load_meshglobal() and hdevmesh obtained from vi:get_devmesh()? Why are they two separate things?
 
clbk_visualcreated in only called once. Do you toggle it somewhere else that is called afterward?
The boolean is toggled in a keypress event. If clbk_visualcreated is only called once, I suppose I leave the hdevmesh in it, and modify hdevmesh in clbk_poststep?
 
Since we're on the subject, a rookie question, what is the difference between hmesh obtained from oapi.load_meshglobal() and hdevmesh obtained from vi:get_devmesh()? Why are they two separate things?
A MESHHANDLE is the representation in the Orbiter core, a DEVMESHHANDLE is in the Graphics Client.
The core pushes the mesh to the GC that usually converts it and uploads it into the graphics card. Once there, modifying the RAM version (the "template") has no side effects on the VRAM version.
This is overly simplified, maybe some GC expert can provide more details.
 
The boolean is toggled in a keypress event. If clbk_visualcreated is only called once, I suppose I leave the hdevmesh in it, and modify hdevmesh in clbk_poststep?
You get your mesh in clbk_visualcreated and you can modify it in clbk_poststep or directly from you key handler I guess.
 
You get your mesh in clbk_visualcreated and you can modify it in clbk_poststep or directly from you key handler I guess.

I toggle the boolean in the keypress event, but it is checked by the loop that I now have in clbk_poststep.

For some reason oapi.edit_meshgroup(hdevmesh, sail_meshgroup, ges) in my loop in clbk_poststep can't see hdevmesh created in clbk_visualcreated.

Code:
function clbk_visualcreated(vis, refcount)

    hdevmesh = vi:get_devmesh(vis,0)

end

function clbk_poststep(simt,simdt,mjd)

    --set sail
    
    for i = 1, #sail_meshgroup do

        ges = {}
        
        if sail_up == true then
            
            ges.flags = GRPEDIT.SETUSERFLAG
            ges.UsrFlag = 3
            
        elseif sail_up == false then
            
            ges.flags = GRPEDIT.SETUSERFLAG
            ges.UsrFlag = 0
            
        end

        oapi.edit_meshgroup(hdevmesh, sail_meshgroup[i], ges)
    
    end

end

I am getting "bad argument #1 to 'edit_meshgroup' (DEVMESHHANDLE expected, got nil)"
 
The output of type(hdevmesh) is 'userdata', queried right before edit_devmesh is called, but Orbiter says it is 'nil':

Screenshot at 2024-12-05 16-10-54.png
 
Strange, maybe the error diagnostic is wrong... Can you PM me your prototype so I can run it with the debugger?
 
If I protect for ges = nil the code works, but I'm damned if I know why:

Code:
function clbk_visualcreated(vis, refcount)

    hdevmesh = vi:get_devmesh(vis, 0)

    ges = {}
    ges.flags = GRPEDIT.SETUSERFLAG
    ges.UsrFlag = 0

end

Code:
function clbk_prestep(simt,simdt,mjd)

    if sail_up == true and ges ~= nil then
       
        ges.UsrFlag = 3
       
    elseif sail_up == false and ges ~= nil then
       
        ges.UsrFlag = 0
       
    end

    for i = 1, #sail_meshgroup do
           
        if ges ~= nil then
           
            oapi.edit_meshgroup (hdevmesh, sail_meshgroup[i], ges)

        end
           
    end

end

I've been burned by this before, where I expect something to run and it seems to but is interpreted as nil. I don't know why protecting from ges = nil is at all necessary.

get_devmesh obviously needs to run after the mesh is loaded in clbk_setclasscaps, and presumably after visuals are created in clbk_visualcreated. My naive assumption was that initial visuals would be loaded before clbk_prestep or clbk_poststep execute for the first time, but counting when ges == nil it seems that they aren't available for only the first time step of the simulation. I don't have an intuitive explanation for why this would be so.
 
Last edited:
Strange, maybe the error diagnostic is wrong... Can you PM me your prototype so I can run it with the debugger?
I again posted just after you did:


I have it working, but I am still not clear on why this happens.
 
I again posted just after you did:


I have it working, but I am still not clear on why this happens.
You should just have to check for hdevmesh ~= nil.
It shows "userdata" in your screenshot because the value is nil only at the beginning of the session and the "nil" debug string is later overwritten (while the Lua error message is never cleared).
using ges ~= nil works because it is initialized at the same time as hdevmesh.
 
Back
Top