A function like "glReadPixels" in DirectX / SharpDX
Asked Answered
S

3

6

I'm searching for a way to read a pixels color at the mousepoint. In OpenGL it was done by calling the function "glReadPixels" after drawing the scene (or parts of it). I want to make a simple color picking routine in the background, for identifing a shapes / lines in 3D Space.

So, is there any equivalent method/function/suggestion for doing the same in SharpDX (DirectX10 / DirectX11) ?

Smidgen answered 12/11, 2012 at 11:37 Comment(0)
D
8

This is perfectly possible with Direct3D11: simply follow these steps:

  • Use DeviceContext.CopySubResourceRegion to copy part from the source texture to a staging texture (size of the pixel area you want to readback, same format, but with ResourceUsage.Staging)
  • Retrieve the pixel from this staging texture using Device.Map/UnMap.

There is plenty of discussion about this topic around the net (for example: "Reading one pixel from texture to CPU in DX11")

Declination answered 12/11, 2012 at 15:6 Comment(1)
Is something like this possible in DX9?Fiesole
S
2

Another option is to use a small compute shader, like :

Texture2D<float4> TextureInput: register(t0);
StructuredBuffer<float2> UVBuffer: register(t1);
RWStructuredBuffer<float4> RWColorBuffer : register(u0);

SamplerState Sampler : register( s0 );

[numthreads(1, 1, 1)]
void CSGetPixels( uint3 DTid : SV_DispatchThreadID )
{ 
float4 c = TextureInput.SampleLevel(Sampler , UVBuffer[DTid.x].xy, 0);
RWColorBuffer [DTid.x] = c;
}

It gives you the advantage of being a bit more "format agnostic".

Process is then like that.

  • Create a small structured buffer for UV (float2) (pixel position/texture size, don't forget to flip Y axis of course). Copy the pixel position you want to sample into this buffer.
  • Create a writeable buffer and a staging buffer (float4). Needs to be same element count as your uv buffer.
  • Bind all and Dispatch
  • Copy writeable buffer into the staging one.
  • Map and read float4 data in cpu

Please note I omitted thread group optimization/checks in compute shader for simplicity.

Slink answered 13/11, 2012 at 6:42 Comment(1)
Interresting and nice one o_o I will test this if i have time for :) Actually, i implemented a ray picking alkorythm with intersection test :)Smidgen
I
1

Since you're using C#, my suggestion would be to use GDI+, as there is no such function like "glReadPixels" in DX. GDI+ offers very easy methods of reading the color of a pixel at your mouse pointer. Refer to stackoverflow.com/questions/1483928.

If GDI+ is a no go, as it isn't very fast, can't you stick to the usual object picking using a "Ray"? You want to identify (I suppose 3-dimensional) shapes/lines, this would be easy using a ray (and check for intersection) to pick them.

Ilmenite answered 12/11, 2012 at 12:36 Comment(3)
[..]object picking using a "Ray"[..] - this was my secound thought, but i thought, if there is any function like "ReadPixels", i could use it - in some cases, color picking can be very good, but you're right, for my needs, rays would do the job. And, GDI+ - i didn't thought about this one.. but you're right, after rendering, i can read the pixel from the control - because i would read only one pixel per frame/update, speed isn't so important. Thanks for your answer :)Smidgen
So, i tried to implement the GDI+ suggestion (i want to give it a try, and it works well :) ) but there's one problem left - i have a WPF Window with a WindowsFormsHost and a Panel in it, drawing to the panels handle via DirectX. But i only get the backcolor of that panel, not whats really in there =/ If i use the desktop window, i get my colors.. any solutions for this =/ ?Smidgen
So, i have a solution - i project the mouse coordinates to screen space and use the "desktop" pixel - so, when my window is on top, i get the requeired pixel. Solution is Ok, but i would prefer to use the "real" output panel..Smidgen

© 2022 - 2024 — McMap. All rights reserved.