Sign in to follow this  
RobMaddison

SOLVED] How to modify the contents of a texture at runtime

Recommended Posts

RobMaddison    1151
Hi all I'm trying to modify the contents of a texture dynamically (using DirectX9). It's an 8bit grayscale texture and what I'm currently doing is locking the texture like this:
D3DLOCKED_RECT lockedRect;
globalBlendMapTexture->LockRect(0, &lockedRect, 0, D3DLOCK_DISCARD);
blendMapData = (BYTE*)lockedRect.pBits;
blendMapPitch = lockedRect.Pitch;
...
int stride = blendMapPitch / width;
blendMapData[(y * blendMapPitch) + (x * stride)] = newValue;
globalBlendMapTexture->Unlock(0);



This works fine. I have something almost identical for getting the colour at a particular point and when I set the new colour and do a lookup, it gives me the new colour as expected. The problem I have is that this new colour doesn't show when doing a lookup in my pixel shader, it still uses the old colour. I load the globalBlendMapTexture using this:
HRESULT hr = D3DXCreateTextureFromFileEx( device, L"some bitmap.bmp",
D3DX_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT,
D3DUSAGE_DYNAMIC, D3DFMT_UNKNOWN, 
D3DPOOL_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT, 
0, NULL, NULL, &globalBlendMapTexture);




As per the MS docs, I've created it using D3DUSAGE_DYNAMIC and D3DPOOL_DEFAULT which should allow lockable textures (that bit works anyway by the looks of it). Is there something else I need to do for the pixel shader to pick up the change? I thought this would have been handled by the driver. Thanks [Edited by - RobMaddison on June 24, 2009 2:49:12 PM]

Share this post


Link to post
Share on other sites
RobMaddison    1151
Thanks for the quick response, I do unlock the texture each time,
I just forgot to add that bit to my snippet.

Should this be possible the way I'm doing it or do I need to use surfaces
or something like that?

Share this post


Link to post
Share on other sites
Evil Steve    2017
Quote:
Original post by RobMaddison
Thanks for the quick response, I do unlock the texture each time,
I just forgot to add that bit to my snippet.

Should this be possible the way I'm doing it or do I need to use surfaces
or something like that?
Nope, textures are the way to go.

All that looks fine to me though - some things you could try:
1. Are you absolutely positive that you're calling SetTexture() to set the correct texture?
2. Any output from the Debug Runtimes?
3. Have you tried using D3DXSaveTextureToFile to save the texture to a file and check that it contains what you expect?
4. If you don't use a pixel shader, and let the fixed function pipeline take over, does it work then?

Share this post


Link to post
Share on other sites
Erik Rufelt    5901
Perhaps you need to regenerate the mipmaps?
I'm not sure whether or not it's done automatically when you change the texture by locking it.. though I'm sure someone else can shed some light on this. =)

Share this post


Link to post
Share on other sites
XVincentX    129
At first, relock texture rect and check if pixel was changed.
Anyway, if you change texture during rendering i think you should reupload it entirely to the GPU. So you should reset texture in the shader, after the change.

Share this post


Link to post
Share on other sites
Evil Steve    2017
Quote:
Original post by Erik Rufelt
Perhaps you need to regenerate the mipmaps?
I'm not sure whether or not it's done automatically when you change the texture by locking it.. though I'm sure someone else can shed some light on this. =)
Actually, that sounds like a likely problem - the texture has a full mipmap chain generated for it when it's loaded, but you only update the top mip level. Either change the 5th parameter to D3DXCreateTextureFromFileEx to 1 instead of D3DX_DEFAULT, or lock and update all surface levels.

Share this post


Link to post
Share on other sites
RobMaddison    1151
Quote:
1. Are you absolutely positive that you're calling SetTexture() to set the correct texture?

This texture is a fundamental part of my rendering (blending) process so it is definitely set.

Quote:
2. Any output from the Debug Runtimes?

I haven't checked these. Mostly because it looks like it is working from within the code, i.e. when I set a pixel to a different value and then retrieve it again from the texture, I get returned the new pixel value as expected.

Quote:
3. Have you tried using D3DXSaveTextureToFile to save the texture to a file and check that it contains what you expect?

I haven't no, that's a good idea, I'll try that a bit later. I have a little test in my pixel shader that indicates whether the relevant pixel has changed colour. So in my code I dynamically change this particular pixel to value 68 and in the shader, I check that pixel to see if it is 68 - if it is, all geometry turns white. If I start the program with 68 in that value in the texture, the relevant geometry is white (so the test works).

Quote:
4. If you don't use a pixel shader, and let the fixed function pipeline take over, does it work then?

My pixel shader is relatively complex, how would I let the fixed function pipeline 'take over'?

Thanks

Share this post


Link to post
Share on other sites
Evil Steve    2017
Quote:
Original post by RobMaddison
Quote:
4. If you don't use a pixel shader, and let the fixed function pipeline take over, does it work then?

My pixel shader is relatively complex, how would I let the fixed function pipeline 'take over'?
Well, you can strip stuff out and render the texture applied to a basic triangle. I know that might be a bit of work to do though...

Share this post


Link to post
Share on other sites
RobMaddison    1151
Quote:
At first, relock texture rect and check if pixel was changed.
Anyway, if you change texture during rendering i think you should reupload it entirely to the GPU. So you should reset texture in the shader, after the change.


I do do that and the pixel does come back from the data as the new value. I don't deliberately reupload it though. I pass the texture to the shader using effect->SetTexture("blendMap", blendTexture); do I need to call that again in order for it to 'reupload'?

Quote:
Perhaps you need to regenerate the mipmaps?
I'm not sure whether or not it's done automatically when you change the texture by locking it.. though I'm sure someone else can shed some light on this. =)

That's an interesting point. The texture is saved without mipmaps and mipmaps are not required for this texture so I should probably load it with 1 as the number of mipmaps (as Steve mentioned).

Thanks

Share this post


Link to post
Share on other sites
RobMaddison    1151
I found out what this issue was after trying various things from the responses. I noticed that after tweaking the pixel and then saving the texture from within the code, it saved as a 24bit texture with the amended pixel in the red channel. This got me thinking about how I'm loading the 8bit texture initially and found out that loading with D3DFMT_UNKNOWN does not preserve the bitplane depth of the original file, it loaded it as a 24bit texture with all my data in the red channel only. So thanks to this post:

http://www.gamedev.net/community/forums/topic.asp?topic_id=450693

...I changed it to D3DFMT_L8 and it worked perfectly.

Thanks again all (including NameThatNobodyElseTook!)

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this