Sign in to follow this  
lucky6969b

Alpha Channel makes opaque objects disappear

Recommended Posts

lucky6969b    1330
Hi,
When I enable alpha channel, some opaque objects gone missing
[code]
m_pDevice->SetRenderState (D3DRS_ALPHABLENDENABLE, true);
m_pDevice->SetRenderState (D3DRS_ZENABLE, true);
[/code]

when I turn off the depth buffer, everything appears in the scene
but transparency was lost.
I have optimized the mesh with Optimize( ATTRSORT....
And using an attribute table, The materials buffer should be correct, otherwise the main object won't appear
when I disable z-buffer.
Any thoughts.. (Post pics later)
Thanks
Jack

Share this post


Link to post
Share on other sites
Paul65    126
Alpha blending has no effect on z buffer. So if a transparent face is in front of something solid but is drawn before it in the rendering, the solid object wont be drawn. Is this maybe your problem? When I've written rendering code before that uses alpha transparency, I've done the rendering in 2 passes, first of all the solid stuff then the transparent.

[quote name='lucky6969b' timestamp='1307117981' post='4819122']
Hi,
When I enable alpha channel, some opaque objects gone missing
[code]
m_pDevice->SetRenderState (D3DRS_ALPHABLENDENABLE, true);
m_pDevice->SetRenderState (D3DRS_ZENABLE, true);
[/code]

when I turn off the depth buffer, everything appears in the scene
but transparency was lost.
I have optimized the mesh with Optimize( ATTRSORT....
And using an attribute table, The materials buffer should be correct, otherwise the main object won't appear
when I disable z-buffer.
Any thoughts.. (Post pics later)
Thanks
Jack
[/quote]

Share this post


Link to post
Share on other sites
DanielDoyle    102
[quote name='lucky6969b' timestamp='1307117981' post='4819122']

[code]
m_pDevice->SetRenderState (D3DRS_ALPHABLENDENABLE, true);
m_pDevice->SetRenderState (D3DRS_ZENABLE, true);
[/code]

[/quote]

Can you post some more code than this? the problem no doubt lies in how you are setting your render states

Share this post


Link to post
Share on other sites
kauna    2922
These opaque objects disappearing don't happen to have alpha component in their texture or perhaps the material values contain zero alpha values?

- basically you should turn on alpha blending just for objects requiring it. So "global" alpha blend enable for every object isn't good approach.
- also, keep in mind that alpha transparency is draw order dependent procedure.

Cheers!



Share this post


Link to post
Share on other sites
lucky6969b    1330
[code]
u32 CPerfectSimView::Draw(float fElapsedTime)
{
CPerfectSimDoc *pDoc = GetDocument();
m_fElapsedTime = fElapsedTime;



pDoc->GetCamera()->Update(m_fElapsedTime, false);

// SetPerspective();
// SetWorld2View();

m_pDevice->SetRenderState(D3DRS_FORCE_DWORD , true);
m_pDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, true );
m_pDevice->SetRenderState( D3DRS_ALPHATESTENABLE, true );


m_pDevice->SetRenderState( D3DRS_SRCBLEND , D3DBLEND_SRCALPHA );
m_pDevice->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA) ;
m_pDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_MODULATE );
m_pDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
m_pDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE );
m_pDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE );
m_pDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE );
m_pDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE );
m_pDevice->SetRenderState( D3DRS_DIFFUSEMATERIALSOURCE, D3DMCS_MATERIAL );

m_pDevice->SetRenderState(D3DRS_ZENABLE, false);
m_pDevice->SetRenderState(D3DRS_ZWRITEENABLE, false);

m_pDevice->SetRenderState(D3DRS_ALPHAREF, 0x00000001);
m_pDevice->SetRenderState(D3DRS_ZFUNC, D3DCMP_FORCE_DWORD | D3DCMP_ALWAYS );
m_pDevice->SetRenderState(D3DRS_AMBIENT, D3DCOLOR_COLORVALUE(0.5, 0.5, 0.5, 1.0));

m_pDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_CCW);


// normalize since objects are being scaled therefore normals aren't correct anymore
m_pDevice->SetRenderState(D3DRS_NORMALIZENORMALS, true);



m_pDevice->SetSamplerState( 0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR );
m_pDevice->SetSamplerState( 0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR );
m_pDevice->SetSamplerState( 0, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR );
m_pDevice->SetRenderState(D3DRS_LIGHTING, true);



m_pDevice->LightEnable(DIRECTIONAL, true);

mFX->SetValue(mhLight, &mLight, sizeof(DirLight));
mFX->SetValue(mAmbientLight, &mLight.ambient, sizeof(D3DXCOLOR));
mFX->SetValue(mDiffuseLight, &mLight.diffuse, sizeof(D3DXCOLOR));
D3DXVECTOR3 v(0.0f, -1.0f, 0.0);
mFX->SetValue(mLightVecW, &v, sizeof(D3DXVECTOR3));




ProcessTask();

pDoc->WHObj->Render();


[/code]
The code is very likely to be wrong. Had no ideas how to correct this mess :) Thanks Jack

Share this post


Link to post
Share on other sites
kauna    2922
Hi,

I took a quick look in your code and I got impression that you are mixing fixed function pipeline stuff and effect stuff. Are you using vertex/pixel shaders?

My knowledge of the old SetRenderState functions start to get rusty, but "[font=CourierNew, monospace][size=2]D3DCMP_FORCE_DWORD" flag is definetely wrong. You seem to use it in several occasions. It is a enum for the compilers. [/size][/font][font=CourierNew, monospace][size=2]However, it shouldn't have significance here or anywhere. [/size][/font]
[font=CourierNew, monospace][size=2]
[/size][/font]
[font=CourierNew, monospace][size=2]
[/size][/font]
[font=CourierNew, monospace][size=2][color=#1C2837][font=arial, verdana, tahoma, sans-serif][color=#000000]m_pDevice[/color][color=#666600]->[/color][color=#660066]SetRenderState[/color][color=#666600]([/color][color=#000000] D3DRS_DIFFUSEMATERIALSOURCE[/color][color=#666600],[/color][color=#000000] D3DMCS_MATERIAL [/color][color=#666600]);[/color][/font][/color][/size][/font]
[font=CourierNew, monospace][size=2]
[/size][/font]
[font=CourierNew, monospace][size=2]The above line doesn't have meaning unless you set [/size][/font]D3DRS_COLORVERTEX to true.


[font="'Segoe UI"][size="2"]As you said, it is a mess. Especially if you mix effect files and shaders with ffp processing. Can you show more code perhaps? Show some shaders?[/size][/font]
[font="'Segoe UI"][size="2"]
[/size][/font]
[font="'Segoe UI"][size="2"]Cheers![/size][/font]

Share this post


Link to post
Share on other sites
lucky6969b    1330
This is the shader code i am using
thanks very much
[code]


struct Mtrl
{
float4 ambient;
float4 diffuse;
float4 spec;
float specPower;
};

struct DirLight
{
float4 ambient;
float4 diffuse;
float4 spec;
float3 dirW;
};

uniform extern float4x4 gWorld;
uniform extern float4x4 gWorldInvTrans;
uniform extern float4x4 gWVP;
uniform extern Mtrl gMtrl;
uniform extern DirLight gLight;
uniform extern float3 gEyePosW;
uniform extern texture gTex;



sampler TexS = sampler_state
{
Texture = <gTex>;
MinFilter = Anisotropic;
MagFilter = LINEAR;
MipFilter = Point;
MaxAnisotropy = 8;
AddressU = WRAP;
AddressV = WRAP;
};


struct OutputVS
{
float4 posH : POSITION0;
float3 normalW : TEXCOORD0;
float3 toEyeW : TEXCOORD1;
float2 tex0 : TEXCOORD2;
float4 color : COLOR0;
};

OutputVS PhongDirLtTexVS(float3 posL : POSITION0, float3 normalL : NORMAL0, float2 tex0: TEXCOORD0)
{
// Zero out our output.
OutputVS outVS = (OutputVS)0;

// Transform normal to world space.
outVS.normalW = mul(float4(normalL, 0.0f), gWorldInvTrans).xyz;

// Transform vertex position to world space.
float3 posW = mul(float4(posL, 1.0f), gWorld).xyz;

// Compute the unit vector from the vertex to the eye.
outVS.toEyeW = gEyePosW - posW;


// Transform normal to world space.
float3 normalW = mul(float4(normalL, 0.0f), gWVP).xyz;
normalW = normalize(normalW);

// Compute the color: Equation 10.2.
//float s = max(dot(gLightVecW, normalW), 0.0f);
//float3 diffuse = s*(gDiffuseMtrl*gDiffuseLight).rgb;
//float3 ambient = gAmbientMtrl*gAmbientLight;
// outVS.color.rgb = ambient + diffuse;
// outVS.color.a = gDiffuseMtrl.a;

// Transform to homogeneous clip space.
outVS.posH = mul(float4(posL, 1.0f), gWVP);

// Pass on texture coordinates to be interpolated in rasterization.
outVS.tex0 = tex0;

// Done--return the output.
return outVS;
}

float4 PhongDirLtTexPS(float3 normalW : TEXCOORD0, float3 toEyeW : TEXCOORD1, float2 tex0 : TEXCOORD2) : COLOR
{
// Interpolated normals can become unnormal--so normalize.
normalW = normalize(normalW);
toEyeW = normalize(toEyeW);

// Light vector is opposite the direction of the light.
float3 lightVecW = -gLight.dirW;

// Compute the reflection vector.
float3 r = reflect(-lightVecW, normalW);

// Determine how much (if any) specular light makes it into the eye.
float t = pow(max(dot(r, toEyeW), 0.0f), gMtrl.specPower);

// Determine the diffuse light intensity that strikes the vertex.
float s = max(dot(lightVecW, normalW), 0.0f);

// Compute the ambient, diffuse and specular terms separatly.
float3 spec = t*(gMtrl.spec*gLight.spec).rgb;
float3 diffuse = s*(gMtrl.diffuse*gLight.diffuse).rgb;
float3 ambient = gMtrl.ambient*gLight.ambient;

// Get the texture color.
float4 texColor = tex2D(TexS, tex0);


// Combine the color from lighting with the texture color.
//float3 color = (ambient + diffuse)*texColor.rgb + spec;
// float3 color = (ambient + diffuse) + spec;
float3 color = (ambient + diffuse);
// if (texColor != 0) {
// color = gMtrl.diffuse*texColor.rgb;
// }

// Sum all the terms together and copy over the diffuse alpha.
// float3 outcolor = color.rgb * 0.5f;
//return float4(color, gMtrl.diffuse.a*texColor.a);
return float4(color, gMtrl.diffuse.a);
}

technique PhongDirLtTexTech
{
pass P0
{
// Specify the vertex and pixel shader associated with this pass.
vertexShader = compile vs_2_0 PhongDirLtTexVS();
pixelShader = compile ps_2_0 PhongDirLtTexPS();
}
}
[/code]

Share this post


Link to post
Share on other sites
kauna    2922
Hi,

I took another quick look to your code and the lines below are "no no" when using vertex/pixel shaders, although they shouldn't matter
[color=#1C2837][size=2][color=#000000]m_pDevice[/color][color=#666600]->[/color][color=#660066]SetRenderState[/color][color=#666600]([/color][color=#000000]D3DRS_LIGHTING[/color][color=#666600],[/color][color=#000000] [/color][color=#000088]true[/color][color=#666600]);[/color][color=#000000]
m_pDevice[/color][color=#666600]->[/color][color=#660066]LightEnable[/color][color=#666600]([/color][color=#000000]DIRECTIONAL[/color][color=#666600],[/color][color=#000000] [/color][color=#000088]true[/color][color=#666600]);[/color][/size][/color]

Also, you are setting sampler states in your code and you also define a sampler in the shader code.

I'd get rid most of the SetRenderStates and move what's necessary to your fx-file.

What you can test is to manually set the alpha value in your shader output and then try the alphablending.

I don't see you setting your gMtrl value anywhere in the code.

Good luck!

Share this post


Link to post
Share on other sites
lucky6969b    1330
Hi,
Thanks for your help first. Really appreciate it :)
I actually set gMtrl inside the render method
[code]
for (int j = 0; j < m_pMesh->m_cAttributes; ++j)
{
int mtrlIndex = m_pMesh->attTable[j].AttribId;
Mtrl m = m_pMesh->GetMaterial()[mtrlIndex];
mFX->SetValue(mhMtrl, &m, sizeof(Mtrl));
.....
[/code]

I am not sure how to set individual pixels to alpha (is that what you meant?) to the mesh
because the mesh is a large chunk by itself. Could you please give me more hints on that?
Thanks
Jack

Share this post


Link to post
Share on other sites
kauna    2922
[color=#1C2837][size=2][color=#000000]float4 [/color][color=#660066]PhongDirLtTexPS[/color][color=#666600]([/color][color=#000000]float3 normalW [/color][color=#666600]:[/color][color=#000000] TEXCOORD0[/color][color=#666600],[/color][color=#000000] float3 toEyeW [/color][color=#666600]:[/color][color=#000000] TEXCOORD1[/color][color=#666600],[/color][color=#000000] float2 tex0 [/color][color=#666600]:[/color][color=#000000] TEXCOORD2[/color][color=#666600])[/color][color=#000000] [/color][color=#666600]:[/color][color=#000000] COLOR
[/color][color=#666600]{[/color][color=#000000]
[/color][color=#000000] ....
[/color][color=#000088]return[/color][color=#000000] float4[/color][color=#666600]([/color][color=#000000]color[/color][color=#666600],[/color][color=#000000] gMtrl[/color][color=#666600].[/color][color=#000000]diffuse[/color][color=#666600].[/color][color=#000000]a[/color][color=#666600]);[/color][color=#000000] [/color][color=#880000]// 1.0f[/color][color=#000000]
[/color][color=#666600]}[/color][color=#000000]
[/color][/size][/color]


Your pixel shader outputs individual fragments. In your shader code, the alpha is coming from "[color=#1C2837][font=CourierNew, monospace][size=2][color=#000000]gMtrl[/color][color=#666600].[/color][color=#000000]diffuse[/color][color=#666600].[/color][color=#000000]a", which you seem to assume to be 1.0 (?).[/color][/size][/font][/color]
[color=#1C2837][font=CourierNew, monospace][size=2][color=#000000]
[/color][/size][/font][/color]
[color=#1C2837][font=CourierNew, monospace][size=2][color=#000000]Basically, if you put 1.0f instead of "[/color][/size][/font][/color][color=#1C2837][font=CourierNew, monospace][size=2][color=#000000]gMtrl[/color][color=#666600].[/color][color=#000000]diffuse[/color][color=#666600].[/color][color=#000000]a" you are saying that all pixels are fully opaque. So no object should go missing when alphablending is enabled.[/color][/size][/font][/color]

Cheers!

Share this post


Link to post
Share on other sites
lucky6969b    1330
Hmmm..... At first blush, the 1.0 doesn't mean anything.. I just commented out the original code.... According to the debugger, the materials were actually correct, as you see in the pictures
Sorry for the misleading comment..... :)
Thanks very much
Jack

Share this post


Link to post
Share on other sites
kauna    2922
[color=#1C2837][size=2]"- also, keep in mind that alpha transparency is draw order dependent procedure. "[/size][/color]
[color=#1C2837][size=2]
[/size][/color]
[color=#1C2837][size=2]Sorry I didn't notice your pictures.[/size][/color]
[color=#1C2837][size=2]
[/size][/color]
[color=#1C2837][size=2]- How about trying to draw the opaque meshes first[/size][/color]
[color=#1C2837][size=2]- and the draw the alpha blended meshes[/size][/color]
[color=#1C2837][size=2]
[/size][/color]
[color=#1C2837][size=2]Cheers![/size][/color]

Share this post


Link to post
Share on other sites
lucky6969b    1330
Yes, I get your point. That's also the problem I have. As the mesh (the main object) is opaque in some parts, and some of them are transparent.
I am not sure how to display them apart.
Thanks... have fun
Jack

Share this post


Link to post
Share on other sites
kauna    2922
Hi,

Do you have one big mesh or lots of different meshes?

If you have one big mesh, try to draw first the opaque parts. Something like " if (mtrl.[font=CourierNew, monospace][size=2]ambient.a == 1.0f)Render()"[/size][/font]

After that, draw it again with a different rule " if (mtrl.[font=CourierNew, monospace][size=2]ambient.a < 1.0f)Render()"[/size][/font]

Without seeing your drawing code I can't give more precise hint.

Cheers!

Share this post


Link to post
Share on other sites
lucky6969b    1330
The warehouse is one big mesh, some parts of it has alpha value less than 1.0, others objects include the trucks and the counter balances and the pallets in yellow

Here is how I load the mesh
[code]
void CMesh::LoadMesh(TCHAR *filename....)
{
D3DXLoadMeshFromX(filename, D3DXMESH_SYSTEMMEM, pDevice,
&adjBuffer, &mtrlBuffer, NULL, &numMtrls, &meshSys);


D3DVERTEXELEMENT9 elems[MAX_FVF_DECL_SIZE];
meshSys->GetDeclaration(elems);

bool hasNormals = false;
D3DVERTEXELEMENT9 term = D3DDECL_END();
for(int i = 0; i < MAX_FVF_DECL_SIZE; ++i)
{
// Did we reach D3DDECL_END() {0xFF,0,D3DDECLTYPE_UNUSED, 0,0,0}?
if(elems[i].Stream == 0xff )
break;

if( elems[i].Type == D3DDECLTYPE_FLOAT3 &&
elems[i].Usage == D3DDECLUSAGE_NORMAL &&
elems[i].UsageIndex == 0 )
{
hasNormals = true;
break;
}
}


// Step 3: Change vertex format to VertexPNT.

D3DVERTEXELEMENT9 elements[64];
UINT numElements = 0;
VertexPNT::Decl->GetDeclaration(elements, &numElements);

ID3DXMesh* temp = 0;
meshSys->CloneMesh(D3DXMESH_SYSTEMMEM | D3DXMESH_32BIT,
elements, pDevice, &temp);
ReleaseCOM(meshSys);
meshSys = temp;


// Step 4: If the mesh did not have normals, generate them.

if( hasNormals == false)
D3DXComputeNormals(meshSys, 0);


// Step 5: Optimize the mesh.
meshSys->Optimize(D3DXMESH_MANAGED |
D3DXMESHOPT_COMPACT | D3DXMESHOPT_ATTRSORT | D3DXMESHOPT_VERTEXCACHE,
(DWORD*)adjBuffer->GetBufferPointer(), 0, 0, 0, &mMesh);
ReleaseCOM(meshSys); // Done w/ system mesh.
ReleaseCOM(adjBuffer); // Done with buffer.

// Step 6: Extract the materials and load the textures.
attTable = new D3DXATTRIBUTERANGE[numMtrls];
mMesh->GetAttributeTable(attTable, &m_cAttributes);

if( mtrlBuffer != 0 && numMtrls != 0 )
{
D3DXMATERIAL* d3dxmtrls = (D3DXMATERIAL*)mtrlBuffer->GetBufferPointer();

for(DWORD i = 0; i < numMtrls; ++i)
{
// Save the ith material. Note that the MatD3D property does not have an ambient
// value set when its loaded, so just set it to the diffuse value.

Mtrl m;

m.ambient = d3dxmtrls[i].MatD3D.Diffuse; //Diffuse;
m.diffuse = d3dxmtrls[i].MatD3D.Diffuse;
m.spec = d3dxmtrls[i].MatD3D.Specular;
m.specPower = d3dxmtrls[i].MatD3D.Power;


mMtrl.push_back( m );

// Check if the ith material has an associative texture
if( d3dxmtrls[i].pTextureFilename != 0 )
{
// Yes, load the texture for the ith subset
IDirect3DTexture9* tex = 0;
char* texFN = d3dxmtrls[i].pTextureFilename;
D3DXCreateTextureFromFile(pDevice, texFN, &tex);

// Save the loaded texture
mTex.push_back( tex );
}
else
{
// No texture for the ith subset
mTex.push_back( 0 );
}
}

}
ReleaseCOM(mtrlBuffer); // done w/ buffer
}
[/code]


Here is how I render the static objects
[code]
void CStaticObject::RenderStaticMesh()
{

mFX->SetMatrix(mhWVP, &(m_matWorld*g_View*g_Proj));
D3DXMATRIX worldInvTrans;
D3DXMatrixInverse(&worldInvTrans, 0, &m_matWorld);
D3DXMatrixTranspose(&worldInvTrans, &worldInvTrans);
mFX->SetMatrix(mhWorldInvTrans, &worldInvTrans);
mFX->SetMatrix(mhWorld, &m_matWorld);

mFX->SetTechnique(mhTech);
UINT numPasses = 0;
mFX->Begin(&numPasses,0);
mFX->BeginPass(0);

for (int j = 0; j < m_pMesh->m_cAttributes; ++j)
{
int mtrlIndex = m_pMesh->attTable[j].AttribId;
Mtrl m = m_pMesh->GetMaterial()[mtrlIndex];
mFX->SetValue(mhMtrl, &m, sizeof(Mtrl));

if (m_pMesh->GetTexture()[j] != 0)
{
mFX->SetTexture(mhTex, m_pMesh->GetTexture()[j]);
}
else
{
;
}
mFX->CommitChanges();
m_pMesh->GetMesh()->DrawSubset(j);
}
mFX->EndPass();
mFX->End();


}

[/code]

Thanks :)
Jack

Share this post


Link to post
Share on other sites
Tom KQT    1704
[quote name='lucky6969b' timestamp='1307260891' post='4819664']
Yes, I get your point. That's also the problem I have. As the mesh (the main object) is opaque in some parts, and some of them are transparent.
I am not sure how to display them apart.
Thanks... have fun
Jack
[/quote]

It will be different subsets then, each subset has a different material, so the transparent subsets and opaque subsets will be separated.
That means that you'll have to for example go from rendering mesh by mesh (while for each mesh you iterate all its subsets) to some sort of a render queue where each entry is a subset of some mesh. You will be also able to sort the queue by materials (by shaders, textures, whatever) which could improve your performance a bit as you can minimise your shader and texture changes. When rendering mesh by mesh you're basically just sorting by a world transform.

I think the StateManager DirectX SDK sample has quite nice "engine" that does that.

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