Sample a texture surface
I am making a fast mouse picking system for my game engine, and I am using a color method. The engine assigns a color to each object and renders a single frame to a textures surface, I would then like to be able to sample that texture for color, based on the mouse coordinates to determine what object the mouse is colliding with. Is this possible? Obviously I have no need to sample the texture in a shader(tex2d).
1. Create a surface with CreateOffscreenPlainSurface in D3DPOOL_SYSTEMMEM, with the same size and format as the render target to which you render your colors
2. After rendering all of your objects to the render target with their colrs/object ID's, use GetRenderTargetData to copy the render target data to your SYSTEMMEM surface.
3. Lock the system surface, and access the texel data at the mouse coordinate that you're interested in.
Note that step #3 may cause a long stall on the CPU, since the CPU will need to wait for the GPU to flush finish all rendering commands. To avoid this, you can use an array of 2-3 system surfaces. Each frame you would copy the render target data to one of the surfaces, and then you would lock the surface that was copied to 1 or 2 frames ago. This adds latency your picking, but prevents stalling. You may also improve performance by using the GPU to write the texel you're interested in to a 1x1 render target, and then copy that to CPU memory.
2. After rendering all of your objects to the render target with their colrs/object ID's, use GetRenderTargetData to copy the render target data to your SYSTEMMEM surface.
3. Lock the system surface, and access the texel data at the mouse coordinate that you're interested in.
Note that step #3 may cause a long stall on the CPU, since the CPU will need to wait for the GPU to flush finish all rendering commands. To avoid this, you can use an array of 2-3 system surfaces. Each frame you would copy the render target data to one of the surfaces, and then you would lock the surface that was copied to 1 or 2 frames ago. This adds latency your picking, but prevents stalling. You may also improve performance by using the GPU to write the texel you're interested in to a 1x1 render target, and then copy that to CPU memory.
Ok, so I feel like I am getting close, but I am not getting correct results.
Does this logic look good?
ps: I am passing 0, 0 for the mouse coordinates just for testing.
Edit: Here is my shader
//Rendered like normal up here
//Create offscreen surface to read surface data
IDirect3DSurface9* offScreenBuffer;
if(_d3dDevice->CreateOffscreenPlainSurface(800, 600, D3DFMT_X8R8G8B8, D3DPOOL_SYSTEMMEM, &offScreenBuffer, 0) != D3D_OK)
ErrorMessenger::ReportMessage("Failed to create off screen surface!", __FILE__, __LINE__);
IDirect3DSurface9* source;
_d3dDevice->GetRenderTarget(0, &source);
if(_d3dDevice->GetRenderTargetData(source, offScreenBuffer) != D3D_OK)
ErrorMessenger::ReportMessage("Failed to GetRenderTargetData!", __FILE__, __LINE__);
//Just verifying the surface data visually
D3DXSaveSurfaceToFile("PickRender.jpg", D3DXIMAGE_FILEFORMAT::D3DXIFF_JPG, offScreenBuffer, 0, 0);
//Lock surface data
D3DLOCKED_RECT* surfaceData = new D3DLOCKED_RECT();//0;
offScreenBuffer->LockRect(surfaceData, 0, D3DLOCK_READONLY);
//Sample for pixel color to determine what object the mouse is colliding with
BYTE* bytePointer = (BYTE*)surfaceData->pBits;
//Get the index where the mouse is located
DWORD index = (mouseX * 4 + (mouseY * (surfaceData->Pitch)));
//Get the color
BYTE red = bytePointer[index];
BYTE blue = bytePointer[index + 1];
BYTE green = bytePointer[index + 2];
BYTE alpha = bytePointer[index + 3];
//Clean up
offScreenBuffer->UnlockRect();
delete surfaceData;
//Find the object that belongs to the color
for(int i = 0; i < _worlds[_views[view].world].Size(); i++)
if(colors == D3DXVECTOR4(red, blue, green, 1))
return i; //Object found, return the index
//Mouse was not colliding with an object.
return NO_INDEX;
Does this logic look good?
ps: I am passing 0, 0 for the mouse coordinates just for testing.
Edit: Here is my shader
float4x4 world : WORLD;
//Camera view and projection
float4x4 cView : VIEW;
float4x4 cProj : PROJECTION;
float4 color : COLOR;
void vsRenderPickScene(float4 iPos : POSITION0,
out float4 oPos : POSITION0)
{
float4 vWorldPos = mul(iPos, world);
float4 vViewPos = mul(vWorldPos, cView);
oPos = mul(vViewPos, cProj);
}
float4 psRenderPickScene() : COLOR0
{
return color;
}
technique RenderPickScene
{
pass p0
{
VertexShader = compile vs_2_0 vsRenderPickScene();
PixelShader = compile ps_2_0 psRenderPickScene();
}
}
I believe with that format the byte order will be either BGRA or RGBA (I forget what ordering is used for D3D9 formats), and you're doing RBGA. Another problem is that you're passing unsigned byte values to the constructor of D3DXVECTOR4, which probably is not what you want. This is just a guess, but uou probably want to normalize the color values to a [0, 1] floating point value (which you can do by dividing by 255).
Also this is unrelated, but there's no reason to dynamically allocate a D3DLOCKED_RECT. Just declare it on the stack, and pass the address of that variable to LockRect.
Also this is unrelated, but there's no reason to dynamically allocate a D3DLOCKED_RECT. Just declare it on the stack, and pass the address of that variable to LockRect.
Ah, that fixed a few things for me. Plus I was being a dum dum when I was setting my color and using int values instead of float, which was getting me only 255's in my color bytes. Thank you for the help! You always have something helpful to contribute lol.
Thats what I thought to, but it apparently doesn't like it, I had to put it on the heap for it to no complain.
Edit: jeez i am losing my mind... ignore my reply to quote!
Also this is unrelated, but there's no reason to dynamically allocate a D3DLOCKED_RECT. Just declare it on the stack, and pass the address of that variable to LockRect.
Thats what I thought to, but it apparently doesn't like it, I had to put it on the heap for it to no complain.
Edit: jeez i am losing my mind... ignore my reply to quote!
This topic is closed to new replies.
Advertisement
Popular Topics
Advertisement