[Dx8] Texture & Blending

Started by
13 comments, last by testt 11 years, 9 months ago
Sure, and finally the problem with blending of two colors isn't resolved. I add a new circles to show the problem when a rendering the texture with :
D3DRS_DESTBLEND=D3DBLEND_ONE

In fact, there is perhaps only one problem and he isn't necessarely to rendering the texture with D3DBLEND_ONE in destblend.

I updated the sources in the original link, or download here the edited sources.
Advertisement
I figured this may be more easily expressed in code so I put it together using DX9 and C++ (I haven't got VB6 or a DX8 SDK, sorry.) But the code should still be easy enough to read since it's mostly the Direct3D parts that matter.

Here it is: http://shilbert.com/...s/BlendTest.zip

This is the interesting part:

[source lang="cpp"]void Draw()
{
g_device->BeginScene();

// Common states we always use
g_device->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
g_device->SetRenderState(D3DRS_LIGHTING, FALSE);
g_device->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);

// Render to 512x512 texture
g_device->SetRenderTarget(0, g_rttSurf);
D3DXMATRIX proj512x512;
D3DXMatrixOrthoOffCenterRH(&proj512x512, 0, 512, 512, 0, -10, 10);
g_device->SetTransform(D3DTS_PROJECTION, &proj512x512);

// Clear all components to zero
g_device->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_ARGB(0,0,0,0), 0, 0);

// Premultiply alpha in the source texture using texture stage
g_device->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);
g_device->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
g_device->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_TEXTURE|D3DTA_ALPHAREPLICATE);

// Set blend mode to (ONE, INVSRCALPHA)
g_device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE);
g_device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);

// Draw textures 1 & 2
DrawTexturedQuad(g_tex1, 0, 0, 512, 512);
DrawTexturedQuad(g_tex2, 0, 0, 512, 512);

// Now switch to the main render target (1024x512)
g_device->SetRenderTarget(0, g_defaultRT);
D3DXMATRIX proj1024x512;
D3DXMatrixOrthoOffCenterRH(&proj1024x512, 0, 1024, 512, 0, -10, 10);

// Clear to some random color
g_device->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 255), 0, 0);

// Reset texture stage settings to default
g_device->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);
g_device->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
g_device->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_CURRENT);
g_device->SetTransform(D3DTS_PROJECTION, &proj1024x512);

// Left side. (render to texture side)
// Draw the back texture, 0.png -- use normal alpha blending
// (doesn't matter since it's opaque)
g_device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
g_device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);

DrawTexturedQuad(g_tex0, 0, 0, 512, 512);

// Draw the offscreen texture we have generated.
// It uses premultiplied alpha so we have to blend appropriately
g_device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE);
g_device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);

DrawTexturedQuad(g_rtt, 0, 0, 512, 512);

// Right side. (control side)
// Now go back and draw each texture on top of one another w/ default alpha blending.
g_device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
g_device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);

DrawTexturedQuad(g_tex0, 512, 0, 512, 512);
DrawTexturedQuad(g_tex1, 512, 0, 512, 512);
DrawTexturedQuad(g_tex2, 512, 0, 512, 512);

// Done with scene, swap buffers, etc.
g_device->EndScene();
g_device->Present(NULL, NULL, NULL, NULL);
}[/source]

I'm drawing to the offscreen render target every frame, but it's the same idea as what you have. Also I did it with a single texture stage, because there is no reason to multiply in vertex color for this example.

Basically when drawing to the offscreen render target:
(1) clear to black w/ zero alpha
(2) set up texture stage 0 to multiply color components by alpha
(3) draw your textures w/ src=one, dest=invsrcalpha

Then when drawing to the target:
(1) reset all texture stages to default
(2) draw your checkerboard backdrop w/ an alpha blend (src=srcalpha, dest=invsrcalpha) or no blending at all
(3) draw the render target texture using src=one, dest=invsrcalpha

I hope that helps.

Here's a screenshot of what it looks like: http://shilbert.com/pics/blendtest.png
I don't understand why I used D3DRS_DESTBLEND=D3DBLEND_ONE to rendering the texture and I don't tried D3DRS_SRCBLEND=D3DBLEND_ONE.. It's so obvious now that I look stupid rolleyes.gif

Thank you very much for all your help, I'd probably still to find the problem. I haven't yet understood all the logics of blending color for the moment but it will come, I already understood the logic that you tried to explain me happy.png

If that doesn't bother you I keep your code in C++, I think this is a good example for me when I will turn to this language.


However, I have a last question because it's the only thing I didn't quite understand. The D3DTA_ALPHAREPLICATE doesn't allow to use vertex color because he take the informations only in the texture ?

I don't understand why I used D3DRS_DESTBLEND=D3DBLEND_ONE to rendering the texture and I don't tried D3DRS_SRCBLEND=D3DBLEND_ONE.. It's so obvious now that I look stupid


I didn't even notice that it was DESTBLEND in your post and not SRCBLEND until you pointed it out. Easy mistake to make.


If that doesn't bother you I keep your code in C++, I think this is a good example for me when I will turn to this language.


No problem. A third of that code is just from a quick start tutorial somewhere on the internet anyway, to make the window & device & such.


However, I have a last question because it's the only thing I didn't quite understand. The D3DTA_ALPHAREPLICATE doesn't allow to use vertex color because he take the informations only in the texture ?


When you do something like D3DTA_TEXTURE | D3DTA_ALPHAREPLICATE, it means it takes the (r,g,b,a) from the texture (the D3DTA_TEXTURE part) and turns it into (a,a,a) (the D3DTA_ALPHAREPLICATE part.) So when you do this:
[source lang="cpp"]
g_device->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);
g_device->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
g_device->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_TEXTURE|D3DTA_ALPHAREPLICATE);
[/source]
It means:
colorarg1 = (r,g,b) from the texture
colorarg2 = sample the alpha from the texture and produce a triplet (a,a,a)
modulate = the output is colorarg1 * colorarg2 = (r,g,b) * (a,a,a) = (r*a, g*a, b*a)

So if the texture at that point is (r,g,b,a) then the overall of that stage is (r*a, g*a, b*a, a). (The alpha processing is just left as default.)
I see, it's simple when it's explained like this happy.png
In fact, I thought the utilisation of D3DTA_ALPHAREPLICATE didn't allow me to use vertex color but rather SRCBLEND=D3DBLEND_ONE. If (for example) I want to change only the alpha of the texture, can I use a another method that modulate the AlphaOp ?

I thought to use D3DTA_TFACTOR (or D3DTOP_BLENDFACTORALPHA) with D3DRS_TEXTUREFACTOR like this :
[source lang="vb"]
D3DDevice8.SetRenderState D3DRS_TEXTUREFACTOR, D3DColorRGBA(255, 255, 255, 100) ' Alpha = 100 for example.

D3DDevice8.SetTextureStageState 0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1
D3DDevice8.SetTextureStageState 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE Or D3DTA_TFACTOR
D3DDevice8.SetTextureStageState 0, D3DTSS_ALPHAARG2, D3DTA_CURRENT[/source]

But the operation seem to work with the black transparent texture.

Edit : Finally I'll see it later, this is not essential for my project, my biggest problem is already solved and I thank you again for that.

This topic is closed to new replies.

Advertisement