Jump to content

  • Log In with Google      Sign In   
  • Create Account


[Dx8] Texture & Blending


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
14 replies to this topic

#1 testt   Members   -  Reputation: 115

Like
0Likes
Like

Posted 22 June 2012 - 03:12 PM

Hi all, (and sorry if my english is bad).

I develop a game in Vb6 with directx8, now I'm stuck on a problem and I don't know if it's correctable.
To explain my problem, I create textures in format A8R8G8B8 (32bits) and filled this with preloaded textures (png).

The problem is that the generated texture doesn't display a correct rendering. For example, if I draw something with transparent pixels, DirectX blending what I draw with the background color (transparent black) and so the texture rendered is darker than it should be.

I can't desactivate alphablending. So I tried different operation of blending (also srcblend and destblend) and I haven't found solutions..

You can download here the source who reproduce my problem and see here an image of the problem.

Thank for any help.


Edit : You can see here exactly le same problem, but he hasn't found a real solution.

Sponsor:

#2 SHilbert   Members   -  Reputation: 647

Like
0Likes
Like

Posted 23 June 2012 - 12:10 AM

So if I am interpreting you correctly, the problem is that doing this sequence:

device.RenderTarget = DeviceBuffer
Draw texture 0 w/ SRCBLEND=SRCALPHA, DESTBLEND=INVSRCALPHA
device.RenderTarget = (an offscreen texture, which starts at transparent black, all values = 0x00000000)
Draw texture 1 w/ SRCBLEND=SRCALPHA, DESTBLEND=INVSRCALPHA
Draw texture 2 w/ SRCBLEND=SRCALPHA, DESTBLEND=INVSRCALPHA
device.RenderTarget = DeviceBuffer
Draw offscreen texture w/ SRCBLEND=SRCALPHA, DESTBLEND=INVSRCALPHA


is not equivalent to this sequence:

device.RenderTarget = DeviceBuffer
Draw texture 0 w/ SRCBLEND=SRCALPHA, DESTBLEND=INVSRCALPHA
Draw texture 1 w/ SRCBLEND=SRCALPHA, DESTBLEND=INVSRCALPHA
Draw texture 2 w/ SRCBLEND=SRCALPHA, DESTBLEND=INVSRCALPHA


And that makes sense, because they aren't equivalent!

If you want to composite two transparent textures into one transparent texture, you are better off working all in pre-multiplied alpha -- both with the loaded textures and the offscreen destination texture. That is, modify your source textures so the R, G, B values are already pre-multiplied by the A values, and draw everything using D3DRS_SRCBLEND=D3DBLEND_ONE and D3DRS_DESTBLEND=D3DBLEND_INVSRCALPHA. If you don't work in pre-multiplied alpha the equation is harder to capture with simple blend operators.

You may be able to avoid pre-multiplying the alpha on your source textures by rendering them with separate blending functions for the color channels & the alpha channel -- use these settings:

D3DRS_SRCBLEND=D3DBLEND_SRCALPHA
D3DRS_DESTBLEND=D3DBLEND_INVSRCALPHA,
D3DRS_SEPARATEALPHABLENDENABLE = TRUE
D3DRS_SRCBLENDALPHA=D3DBLEND_ONE
D3DRS_DESTBLENDALPHA=D3DBLEND_INVSRCALPHA.


When drawing the offscreen texture to the final device buffer you must disable the separate alpha blending & just use D3DRS_SRCBLEND=D3DBLEND_ONE, D3DRS_DESTBLEND=D3DBLEND_INVSRCALPHA.

I'm not sure if D3D8 supports this feature though -- I only have the D3D9 docs handy.

#3 testt   Members   -  Reputation: 115

Like
0Likes
Like

Posted 23 June 2012 - 04:54 AM

Yes, I thought to use D3DRS_SEPARATEALPHABLENDENABLE but D3D8 don't support this. I've searched a alternative to this but I don't find solution.

#4 SHilbert   Members   -  Reputation: 647

Like
0Likes
Like

Posted 23 June 2012 - 01:48 PM

You should be able to accomplish it with with texture stage states.

For example, I think if you do add second color stage with

D3DTSS_COLOROP = D3DTOP_MODULATE
D3DTSS_COLORARG1 = D3DTA_CURRENT
D3DTSS_COLORARG2 = D3DTA_TEXTURE | D3DTA_ALPHAREPLICATE

...you can get the same effect. You only need to use this extra stage when rendering from non-premultiplied alpha textures, like your textures from 1.png and 2.png.

You can also do the premultiplication 'offline' by modifying your texture files before you load them, or lock the texture after loading and do the premultiplication then.

Or you could switch to DX9, which is close to 10 years old at this point and enjoys near universal support. Posted Image Don't know if that is feasible in VB6 though, I don't know much about that ecosystem. This guy seems to have a library for using DX9 in VB (see post #14.)

#5 testt   Members   -  Reputation: 115

Like
0Likes
Like

Posted 24 June 2012 - 06:46 AM

I see, but when you add second color stage, you use a different texture (example : stage0 for 1.png and stage1 for 2.png) or is the same texture ?

I don't want to modify the texture because I'll use several times (many textures and sometimes the same texture), I think it's problematic and longer to load after. It's even why I create a texture to preload all once.

Also, I already found the guy who propose a librarie for dx9 in vb6, but it's incomplete (For example, I use CreateTextureFromFileInMemoryEx and he isn't added). If I don't found solution for this, I migrate probably to vb.net (It's my last solution).

#6 mhagain   Crossbones+   -  Reputation: 7436

Like
0Likes
Like

Posted 24 June 2012 - 06:53 AM

You can set the same texture to as many stages as you wish if that's what you need to do.

It appears that the gentleman thought C++ was extremely difficult and he was overjoyed that the machine was absorbing it; he understood that good C++ is difficult but the best C++ is well-nigh unintelligible.


#7 testt   Members   -  Reputation: 115

Like
0Likes
Like

Posted 24 June 2012 - 12:50 PM

Yes, I know it's possible, but I don't understand exactly how Shilbert told me to do that. Use the same texture in 2 stages to separate opaque pixel and transparent pixel (with a different blending operation for each) or 2 textures in 2 stages for blending between them ?

#8 SHilbert   Members   -  Reputation: 647

Like
0Likes
Like

Posted 24 June 2012 - 02:47 PM

Yes, I know it's possible, but I don't understand exactly how Shilbert told me to do that. Use the same texture in 2 stages to separate opaque pixel and transparent pixel (with a different blending operation for each) or 2 textures in 2 stages for blending between them ?


The same texture in 2 stages. The goal is to multiply the texture's normal RGB values by the texture's A value before it even gets to the blending stage. This makes the your texture effectively have "premultiplied alpha" at runtime, so you don't have to do it at or before load time. This isn't a pre-pass step, it's something you do every render.

It's been ages since I worked with texture stages but I am pretty sure this sort of approach will work.

If you don't care about vertex colors you can also do it in one stage like this, I think:

(Stage 0)
Texture = (your source texture)

D3DTSS_COLOROP = D3DTOP_MODULATE

D3DTSS_COLORARG1 = D3DTA_TEXTURE

D3DTSS_COLORARG2 = D3DTA_TEXTURE | D3DTA_ALPHAREPLICATE


Edited by SHilbert, 24 June 2012 - 02:49 PM.


#9 testt   Members   -  Reputation: 115

Like
0Likes
Like

Posted 26 June 2012 - 04:00 PM

Hi and sorry for my absence (I had some problems with my pc).

This blending stage seem to work with the RGB blending, but the Alpha stay problematic. See here.
There are two problems, the alpha is too low and the blending of two color is incorrect when one of two isn't opaque (In fact, in the situation the opaque color became transparent).

I understood what you want to do but I'm not sure that the stage 1 is useful here (The ColorOp in the stage 1 is disable by default, so in this situation is ineffective, no ?).


Edit : The problem with blending of two colors has been resolved, there remains the problem of alpha too low.. See here.

Edited by testt, 27 June 2012 - 02:52 PM.


#10 SHilbert   Members   -  Reputation: 647

Like
0Likes
Like

Posted 27 June 2012 - 09:51 PM

Hi and sorry for my absence (I had some problems with my pc).

No worries!

Edit : The problem with blending of two colors has been resolved, there remains the problem of alpha too low.. See here.

Hmm, it looks like it is a lot closer! It's like somehow it's rendering as if the alpha is squared (i.e., always less than it ought to be unless alpha = 1.) It's almost as if the alpha is getting premultiplied by itself along with the color parts. Could you maybe post the source as it is now? I'd like to take a look at all of the render states together.

#11 testt   Members   -  Reputation: 115

Like
0Likes
Like

Posted 28 June 2012 - 04:59 AM

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.

#12 SHilbert   Members   -  Reputation: 647

Like
0Likes
Like

Posted 28 June 2012 - 09:14 PM

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

#13 testt   Members   -  Reputation: 115

Like
0Likes
Like

Posted 29 June 2012 - 05:31 AM

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 Posted Image

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 Posted Image

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 ?

#14 SHilbert   Members   -  Reputation: 647

Like
0Likes
Like

Posted 29 June 2012 - 07:41 AM

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

#15 testt   Members   -  Reputation: 115

Like
0Likes
Like

Posted 29 June 2012 - 10:15 AM

I see, it's simple when it's explained like this Posted Image
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.

Edited by testt, 29 June 2012 - 07:51 PM.





Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS