Getting an up-to-date camera transform

I’m trying to improve RenderCam, but there doesn’t seem to be any decent way to get an up-to-date object transform for rendering – i.e. a transform that’s not one frame behind.

It’s the same problem as in this thread: Dealing with the one frame lag when visualising dynamic bodies

The root of the problem is:
A) There’s no script callback after physics update but before render update
B) The render script doesn’t have access to ‘go.’ functions.

From what I can tell, the relevant part of the engine’s update loop goes like this:

  1. script update
  2. script on_message (get message sent to self on update)
  3. physics update (get physics messages in on_message)
  4. render script can get message from active camera component
  5. render script update

Object transforms are updated between each of the first 4 steps.

  • Anytime you move the camera, its world transform becomes out of date until the next point in the engine’s update cycle.

  • So, if your camera is attached to a physics object, or if you move it during any physics message response, you have no way of getting it’s updated transform.

  • The built-in camera component does work—it messages its View and Projection matrices to the render script after the physics update—the problem is, only one active camera does this, and I want to support multiple cameras at once (for split-screen, minimaps, rear-view mirrors, etc.).

Currently my camera sends a message to itself in update(), and updates its position and stuff when it gets that message (making its world transform out-of-date). I haven’t tested the exact reasons for that in a while, but I recall it jittered like crazy if I didn’t do it. The only thing after that to hook into is physics messages. So the only current solution I can see, is to do a physics raycast every frame and get the transform in the “ray_cast_missed” message response. That’s a bit more “hacky” than I’m willing to be at the moment.


Possible solutions

The easiest fix I can see is to allow render scripts to get info about objects. In my specific case, if the render script could do go.get_world_transform(), then I think my problem would be solved. (Of course access to other getters would be good.)

The other way is to add another “post_update” script callback, called after physics are updated but before rendering.

3 Likes

A nice post_update would be lovely, and would solve a lot of issues like this!

1 Like

This is probably not what you expect, but…
You can do this in render script:

if shared_state_module.some_go_context then -- context == self
   local current = _G[3700146495]
   _G[3700146495] = shared_state_module.some_go_context
   local result = go.get_world_transform()
   _G[3700146495] = current
   print(result)
end

or make extension:

static
int execute_in_context(lua_State *L) {
   dmScript::GetInstance(L);
   int self = dmScript::Ref(L, LUA_REGISTRYINDEX);

   lua_pushvalue(L, 2);
   dmScript::SetInstance(L);

   lua_call(L, lua_gettop(L) - 1, LUA_MULTRET);
   int results_count = lua_gettop(L);

   lua_rawgeti(L, LUA_REGISTRYINDEX, self);
   dmScript::SetInstance(L);
   dmScript::Unref(L, LUA_REGISTRYINDEX, self);

   return results_count;
}

what used like this:

extension.execute_in_context(run_what, in_which_context, param1, param2, etc...))
2 Likes

Haha! You know, I wondered if there was some sneaky way to change the context like this, but hadn’t looked for it yet. I probably wouldn’t have figured out what that “3700146495” key was for though.
Thanks! I might just use this.

1 Like

It’s different for HTML5?

1 Like

Lua 5.1 vs LuaJIT

1 Like

@britzl So is this something I can rely on, or is it likely to get broken at some point?

I think using that ids from lua is bad idea)
This is undocumented feature, and can be changed in future.

You should use native extension for that.

I used it a lot. And it worked))

3 Likes

What @d954mas said! Don’t rely on it! The native extension approach is reliable though. I’m making a note to consider this to be integrated in the engine somehow.

3 Likes

Sometimes you have to though. In some instances calling a Native Extension will switch the context so you will have to “force it back”, issue I reported on it https://github.com/defold/editor2-issues/issues/2616

I haven’t heard anyone else mentioning this so maybe it isn’t very common but I stumble upon it from time to time.

(sorry for the necro)

2 Likes

I’d like to look into this. Could you please provide a minimal project reproducing this behaviour?

Already included in the issue :slight_smile:

1 Like

Thanks!

I have transferred the issue to the Defold repo: https://github.com/defold/defold/issues/5000