Alpha channel

Started by
30 comments, last by Nik02 12 years ago
How to setup textures alpha channel? I found only this:
LPDIRECT3DTEXTURE9 m_pTexture;

// Create an alpha texture
D3DXCreateTexture(m_d3dDevice, 128, 128, 0, D3DUSAGE_RENDERTARGET,
D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, &m_pTexture);

// Initialize the alpha channel
int yGrad, xGrad;
D3DLOCKED_RECT lockedRect;

if(SUCCEEDED(pTexture->LockRect(0, &lockedRect, NULL, D3DLOCK_DISCARD )))
{
m_pRGBAData = new DWORD[128*128];
if( m_pRGBAData != NULL )
{
for( DWORD y=0; y < m_dwHeight; y++ )
{
DWORD dwOffset = y*m_dwWidth;
yGrad = (int)(((float)y/(float)m_dwWidth) * 255.0f);

for( DWORD x=0; x < m_dwWidth; x )
{
xGrad = (int)(((float)x/(float)m_dwWidth) * 255.0f);

DWORD b = (DWORD)(xGrad + (255 - yGrad))/2 & 0xFF;
DWORD g = (DWORD)((255 - xGrad) + yGrad)/2 & 0xFF;
DWORD r = (DWORD)(xGrad + yGrad)/2 & 0xFF;
DWORD a = (DWORD)(xGrad + yGrad)/2 & 0xFF;

lockedRect.pBits[dwOffset+x] = ((a<<24L)+(r<<16L)+(g<<8L)+(b));
x++;
}
}
}
pTexture->UnlockRect(&lockedRect);
}


m_pd3dDevice->SetTexture(0, m_pTexture);

// Texture stage states
m_pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
m_pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);

m_pd3dDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);

m_pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
m_pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE);

m_pd3dDevice->SetTextureStage

but this sample doesn't work...
Advertisement
IIRC render target usage is incompatible with managed pool allocation. Other than that, the code should generate a square texture with linear gradients for all channels, including alpha.

Note that texture scanline width (or Pitch) is not guaranteed to be same as width*bytesPerPixel; this code assumes that it is but this is often an incorrect assumption. The locked rect structure contains the Pitch field for this.

The [color=#000000]m_pRGBAData array is not needed; D3D will allocate (or give) the scratch space from system memory for you when you lock resources. The pointer to the scratch space is in the locked rect structure's pBits field.

The x loop counter is incremented in a funny way; usually, the incrementation is done in the "for" statement:

[font=courier new,courier,monospace]for (int x = 0; x < something; ++x) {}[/font]

Define "doesn't work".

Niko Suni



int yGrad, xGrad;
D3DLOCKED_RECT lockedRect;

if(SUCCEEDED(LOCATIONS.g_pMeshTextures->LockRect(0, &lockedRect, NULL, D3DLOCK_DISCARD )))
{

for( DWORD y=0; y <lockedRect.Pitch ; y++ )
{
DWORD dwOffset = y*lockedRect.Pitch;
yGrad = (int)(((float)y/(float)lockedRect.Pitch) * 255.0f);

for( DWORD x=0; x < lockedRect.Pitch; x++ )
{
xGrad = (int)(((float)x/(float)lockedRect.Pitch) * 255.0f);

DWORD b = (DWORD)(xGrad + (255 - yGrad))/2 & 0xFF;
DWORD g = (DWORD)((255 - xGrad) + yGrad)/2 & 0xFF;
DWORD r = (DWORD)(xGrad + yGrad)/2 & 0xFF;
DWORD a = (DWORD)(xGrad + yGrad)/2 & 0xFF;

lockedRect.pBits[dwOffset+x] = ((a<<24L)+(r<<16L)+(g<<8L)+(b));

}
}
}
LOCATIONS.g_pMeshTextures->UnlockRect((UINT)&lockedRect);



// Texture stage states
g_pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
g_pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);

g_pd3dDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);

g_pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
g_pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE);

g_pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);


I have error one here:
lockedRect.pBits[dwOffset+x] = ((a<<24L)+(r<<16L)+(g<<8L)+(b));
-The y coordinate range is 0...height-1. You are now writing past the allocated area, and if you're lucky, you get an access violation + crash your program.
-The pBits field is a void pointer; the compiler cannot determine the width of the elements automatically if you treat it as an array. Cast it to a unsigned char* before performing pointer arithmetic.
-The x coordinate should still span just the width of the texture; pitch can be the same or greater than width*bytes per pixel (you can't really assume anything else).
-Assuming x and y span the width and height of the texture respectively, the unsigned char (or byte) pointer for a 32-bit texel at x,y can be found as follows:

y * pitch + x * 4

...since each pixel is 4 bytes wide, assuming the format is a8r8g8b8, and each scanline is pitch bytes wide in memory. The byte pointer can be cast to UINT* so you can easily dereference a whole UINT. Alternatively, you can also write the argb data directly to the pointer by treating it as a byte array.

Niko Suni

blink.png well...looks like that i didn't understand anything....but no, something i understand, but not enough to write correct code...is there maybe a working sample about texture alpha? Or some lessons? I just need working code, cause trying to understand code, that don't work its hard...
Alpha data is just an another byte in the texels (assuming a8r8g8b8), just like red, green and blue.

Do you understand the difference between "void*" and "unsigned char *" (or pointer to any data type), and how the pointer type affects the way the array element addresses are calculated? It is best to start from the language basics before doing more advanced stuff with D3D.

Niko Suni

[font=courier new,courier,monospace]for (uint y = 0; y < height; y++)[/font]
[font=courier new,courier,monospace]for (uint x = 0; x < width; x++)[/font]
[font=courier new,courier,monospace]{[/font]
[font=courier new,courier,monospace] unsigned char* pBytes = (unsigned char*)lr.pBits; // lr = D3DLOCKED_RECT you get from locking the texture[/font]
[font=courier new,courier,monospace] uint offset = y * lr.Pitch + x * 4; // as explained in earlier post[/font]
[font=courier new,courier,monospace] pBytes[offset] = alpha; // alpha, red, green, blue are unsigned chars 0...255[/font]
[font=courier new,courier,monospace] pBytes[offset + 1] = red;[/font]
[font=courier new,courier,monospace] pBytes[offset + 2] = green;[/font]
[font=courier new,courier,monospace] pBytes[offset + 3] = blue;[/font]
[font=courier new,courier,monospace]}[/font]

Niko Suni

http://msdn.microsof...7(v=vs.85).aspx
http://msdn.microsoft.com/en-us/library/windows/desktop/bb172231(v=vs.85).aspx

Niko Suni

I set pBytes[offset + 3] = 255;, cause if i understand correctly its must be alpha channel, but now i can see only black rectangles on textures.

pBytes[offset] = alpha; -hmm maybe not, cause i set it to 255 - and saw blue rectangles....
Yea, the bytes are other way around (I used less than 1 minute to write the example loops) :)

Anyway, you need to enable alpha blending render state as well, in order to control the opacity of the drawn geometry with the alpha data.

Your texture stage state setup seems ok, but I recommend moving to pixel shaders as soon as possible to get more control and flexibility.

Niko Suni

This topic is closed to new replies.

Advertisement