For an existing game (VBS3) I'd like to write a plugin which exports all the rendered pixels with their world position (basically something like a LIDAR point cloud).

Actually I don't need the position of each pixel, instead I could also use the application's internal collision checking system with equally spaced ray endpoints, but it turned out that this approach is way too slow and coarse.

The game provides a callback which gets called whenever the back buffer has been filled. Then this callback provides references to a depth buffer and a render target, both of type IDirect3DSurface9.

As a first shot I just wanted to do it like Andon M. Coleman described in [1] but my problem is that the IDirect3DDevice9 linked to the surfaces only returns identity matrices when I call GetTransform() on it with types D3DTS_PROJECTION and D3DTS_VIEW.

Therefore I suppose the application does not use those matrices at all and instead does all the matrix / projection stuff internally. Am I right? Is this common? And are there other approaches I could take?

Thanks in advance!

[1] https://stackoverflow.com/questions/32227283/getting-world-position-from-depth-buffer-value


SetTransform/GetTransform only apply if the programmer is using the legacy fixed-function pipeline. They don't apply at all if a vertex shader is used, so yes, I would say that it is very common to not use them.

Assuming that shaders are used, these matrices will instead be stored in vertex shader constant registers, of which there are typically 256 (legacy hardware may have fewer). Each register is 4 floats and a matrix therefore consumes 4 registers.

This holds true even if the Effects framework is used, which typically doesn't expose registers to the programmer but is nonetheless just a wrapper around the underlying register-based API.

To retrieve the contents of these registers you would use IDirect3DDevice9::GetVertexShaderConstantF.

Unfortunately there is no standard or even convention for which registers matrices typically go into. Some programs may also store each of the required matrices separately whereas other programs may just store a single concatenated MVP.

To complicate things slightly more, programs may also apply custom transforms that are not even matrix-based at all; part of the flexibility of vertex shaders is that the programmer is not limited to the built-in fixed transforms, so you should expect this on occasion.

So what you're going to have to do is make a number of GetVertexShaderConstantF calls, examine the results, and experiment until you hopefully find something that works, but be prepared to accept that if the program does anything more unusual than just replicating the behaviour of the 3 fixed-pipeline matrices you may never find anything that works.

Finally, you should be aware that GetVertexShaderConstantF may involve a round-trip to the GPU which will impact your performance (I would expect that drivers would cache registers locally and flush to the GPU in batches so this may not be such a big deal, but I wouldn't depend on it).

  • \$\begingroup\$ This is very helpful, thanks a lot! From what I've seen so far concerning the game API, I don't expect the developers to use any standard way, even if there was one ... One additional question is left though: the depth buffer contains values in range [0,1]. If I manage to retrieve the necessary information to recreate the transformation matrix/matrices via game API, may I combine those with the depth values? Or does the depth buffer only contain garbage and I have to get the depth values from somewhere else as well? \$\endgroup\$ – Apollo13 Jun 1 '17 at 12:58
  • \$\begingroup\$ @Apollo13 - I suggest asking that as a separate question in it's own right; SE comments are primarily intended for clarifications rather than for extended discusions or follow-up Q&As (SE differes from discussion forums in this regard) so you'll get better attention, better answers and no risk of moderator intervention by asking another question. \$\endgroup\$ – Maximus Minimus Jun 1 '17 at 13:14
  • \$\begingroup\$ Ok, thank you again for your advice. Didn't think this justifies a new question ;) \$\endgroup\$ – Apollo13 Jun 2 '17 at 9:10
  • \$\begingroup\$ Ok, according to another post I should be able to reconstruct the projection matrix from the frustum values (I have access to left angle, right angle, top angle, bottom angle, near plane, far plane) Is this enough? I calculated the near plane vertices and used those with this template: songho.ca/opengl/files/gl_projectionmatrix_eq16.png But apparently this is wrong - my depth values are just black and white (no grey pixels) afterwards... \$\endgroup\$ – Apollo13 Sep 27 '17 at 18:12

Your Answer

