Please, I need the opinion of some experts in blending here

Started by
3 comments, last by adriano_usp 19 years, 2 months ago
Hi, I have been making some blending tests and I came across an eccentric effect (at least for me). I never had noticed that. I just used these render states for blending: g_pd3dDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_DESTCOLOR); g_pd3dDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ZERO); but it seems that the blending assumes a different behavior when the camera's eye moves from the positive z-space to the negative z-space (and vice versa). I'm referring to the z-space from the world space (not from the camera/view space). I programmed a very simple sample to show that. It is just a camera rotating around a hill in a terrain. The code sample is very small and comprehensible. Please, download it at: www.adrianojmr.ubbi.com.br/testblending.js After downloading it, just chance its extension from .js to .zip Please, does somebody know why that effect happens? Shouldn't the blending have the same behavior in the entire path of the camera? Thank you in advance. [Edited by - adriano_usp on February 9, 2005 8:12:40 PM]
Advertisement
I haven't run the demo, but I can probably tell you what's going on.

Your blending is set to modulate. ie: resultcolor = newcolor * framebuffer color.

Lets say your frame buffer is white, and your ground and hill are 50% grey.

If you camera is facing such that the faces come back to front, you'll draw some ground (white*50% = 50%), then you'll draw the hill in front of the ground (50% * 50% = 25%). If your culling is set to none, you'll likely get the other side of the hill too (25% * 50% = 12.5%).

When facing such that the ground is drawn front to back, you'll draw the front of the hill (white * 50% = 50%). Z rejection will cause the back of the hill and the ground behind it to never be drawn.

What you're actually getting is a crude overdraw meter, where darker regions indicate larger quantities of overdraw.


Hi Namethatnobodyelsetook, thank you much for the explanation.

But I still have some doubts. I will detail more:
The hill and the terrain are the same mesh. It is like a Mexican hat. The hill is at the origin of the 3D space. The camera's target is at the origin too. The camera's eye moves in a circular path around the origin, above the "hat's brim".

Since the depth buffer method compares distances considering the z-axis from the view/camera space (not from the world space), shoudn't I see the overdraw on the entire path of the camera?

...or this has nothing to do with the z-buffer?

Thanks again.

Edit: OK, OK! I understood! [smile]. But how could I invert the order of the polygons (before z-buffer checking) to avoid that?

Edit2:
Humm... sorting different objects by depth is easy. The problem is that the hill and the terrain are the same mesh. Probably I will have to lock/unlock the VB/IB, sorting the polygons by depth and render them using DrawIndexedPrimitive method... Doesn't Direct3D have some sorting function for that?

[Edited by - adriano_usp on February 9, 2005 10:55:11 PM]
This is the biggest annoyance of alpha blended objects. There is no simple solution that's always good. For landscape, you could draw once with colorwriteenable set to 0, then renable color and draw again. The first pass would fill in all the Z values. Typically you want to draw one pass, then multiply on a second pass, so the first pass would be non-alphablended and generate all those precious Z values. Of course, once you're doing a modulative second pass, trying to mix with fog goes all to hell.

You could also generate an index buffer on the fly if you're doing a heightmap style landscape.
Thank you much Namethatnobodyelsetook.

OK, it worked when I used only the terrain. But, as you said, that blending problem is really annoying. There is no general solution for that.
Unfortunately, I decided to make new tests... and the problem returned [embarrass]:

I put a lake around the hill and created a mirror function to reflect the hill (and the terrain behind it) on the lake.
What I see now is an undesired blending at the reflected region, but only when the camera is in the positive z-space. Well, it seems the same problem, but I'm not getting to set D3DRS_COLORWRITEENABLE correctly. Please, in the following code, where would you set the D3DRS_COLORWRITEENABLE to solve that?

//-----------------------------------------------------------------------------// Camera()//-----------------------------------------------------------------------------VOID Camera(){    D3DXMATRIXA16 matWorld;    D3DXMatrixIdentity(&matWorld);    g_pd3dDevice->SetTransform( D3DTS_WORLD, &matWorld );    D3DXVECTOR3 vEyePt( 0.0f, 400.0f,-1500.0f );    D3DXVECTOR3 vLookatPt( 0.0f, 300.0f, 0.0f );     D3DXVECTOR3 vUpVec( 0.0f, 1.0f, 0.0f );    D3DXMATRIX R;    D3DXMatrixRotationY( &R, timeGetTime()/1500.0f );    D3DXVec3TransformCoord( &vEyePt, &vEyePt, &R );    D3DXMATRIX matView;    D3DXMatrixLookAtLH( &matView, &vEyePt, &vLookatPt, &vUpVec );    g_pd3dDevice->SetTransform( D3DTS_VIEW, &matView );    D3DXMATRIXA16 matProj;    D3DXMatrixPerspectiveFovLH( &matProj, D3DX_PI/4, 1.0f, 1.0f, 10000.0f );    g_pd3dDevice->SetTransform( D3DTS_PROJECTION, &matProj );}//-----------------------------------------------------------------------------// Mirror()//-----------------------------------------------------------------------------VOID Mirror(){    D3DXMATRIXA16 matViewSaved;    g_pd3dDevice->GetTransform( D3DTS_VIEW, &matViewSaved );    D3DXVECTOR3 vPoint(0,250,0);    D3DXVECTOR3 vNormal(0,1,0);    D3DXMATRIXA16 matView, matReflect;    D3DXPLANE plane;    D3DXPlaneFromPointNormal( &plane, &vPoint, &vNormal );    D3DXMatrixReflect( &matReflect, &plane );    D3DXMatrixMultiply( &matView, &matReflect, &matViewSaved );    g_pd3dDevice->SetTransform( D3DTS_VIEW, &matView );    g_pd3dDevice->SetClipPlane( 0, plane );    g_pd3dDevice->SetRenderState( D3DRS_CLIPPLANEENABLE, 0x01 );    g_pd3dDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_CW );    g_pd3dDevice->Clear(0, 0, D3DCLEAR_ZBUFFER, 0, 1.0f, 0);    Terrain->RenderMesh();        g_pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);    g_pd3dDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_CCW );    g_pd3dDevice->SetTransform( D3DTS_VIEW, &matViewSaved );    // Up to here, we notice that the hill blends with the water behind it.     // We solve that by rendering the parts of the terrain that are above the clip plane.    Terrain->RenderMesh();    g_pd3dDevice->SetRenderState( D3DRS_CLIPPLANEENABLE,  0x00 );}//-----------------------------------------------------------------------------// Render()//-----------------------------------------------------------------------------VOID Render(){    g_pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(200,200,255), 1.0f, 0 );        if( SUCCEEDED( g_pd3dDevice->BeginScene() ) )    {        Camera();		        Terrain->RenderMesh();        g_pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);        g_pd3dDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_DESTCOLOR);        g_pd3dDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ZERO);        Water->RenderMesh();        Mirror();        g_pd3dDevice->EndScene();    }    g_pd3dDevice->Present( NULL, NULL, NULL, NULL );}



It is just a test, so I'm not using the stencil buffer.

Thank you much in advance.

This topic is closed to new replies.

Advertisement