Jump to content
  • Advertisement
Sign in to follow this  
LevyDee

Sample a texture surface

This topic is 2495 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

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).

Share this post


Link to post
Share on other sites
Advertisement
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.

Share this post


Link to post
Share on other sites
Ok, so I feel like I am getting close, but I am not getting correct results.


//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();
}
}

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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.


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!

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!