• Advertisement
Sign in to follow this  

Transparency + X-Files

This topic is 3611 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Alrighty, so if I'm not mistaken xfiles can have transparency, right? I believe I had seen before, that they were capable of being set to some transparent alpha value. Anyhow, how do I accomplish something such as that? I'm asking because I'm thinking about doing a simple single player RPG on the side, where I'll have the player models walking around a level on a specified camera angle. Now, the dilemna I'm going to be facing is that when the person walks under a tree, from the line of sight, how am I going to be able to handle some sort of transparency on-the-fly, of that xfile that he's hidden under? or near? ** I will mention, it doesn't have to be directly under, but anything I find obstructing the view of the player? Thanks in advance. -Quinn

Share this post


Link to post
Share on other sites
Advertisement
Are you using fixed-function or shaders? For shaders having transparency is easy: simply output a color value with alpha < 0 and make sure alpha blending is enabled in the device render states. If you're using the effects framework you can include those render states right in the fx file, and keep everything wrapped up in one tidy package.

With FFP you will have to set texture stage states that use data from either vertices, materials, textures, or a constant value to determine the final alpha value. For your purposes using a constant alpha value is probably best, as it won't require you to dynamically modify vertices or textures.

Share this post


Link to post
Share on other sites


void MeshAlpha(LPDIRECT3DDEVICE9 p_d3dDevice, float Alpha)
{

D3DXMATRIX matRotation,matTranslation;
D3DXMatrixTranslation(&matTranslation,0,0,0);
p_d3dDevice->SetTransform(D3DTS_TEXTURE0,&(matTranslation));

p_d3dDevice->SetTextureStageState( 0, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_COUNT2 );

for( DWORD i=0; i< NumMaterials; i++ )
{
// Set the material and texture for this subset
Materials.Diffuse.a = Alpha;
p_d3dDevice->SetMaterial( &Materials );
p_d3dDevice->SetTexture( 0, Textures );
p_d3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE,true); //alpha blending enabled
p_d3dDevice->SetRenderState(D3DRS_SRCBLEND,D3DBLEND_SRCALPHA); //source blend factor
p_d3dDevice->SetRenderState(D3DRS_DESTBLEND,D3DBLEND_INVSRCALPHA); //destination blend factor


// Draw the mesh subset
Mesh->DrawSubset( i );
}
D3DXMatrixIdentity(&matRotation);
p_d3dDevice->SetTransform(D3DTS_TEXTURE0,&(matRotation));
p_d3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE,false);
p_d3dDevice->SetTextureStageState( 0, D3DTSS_TEXTURETRANSFORMFLAGS,
D3DTTFF_DISABLE );

}





I basically copied my CMesh - MeshAlpha function in here. So, basically, what I did with my MeshAlpha function is all I need right? I'm not using shaders, I may learn shaders in the future, but this is something minimal I'm trying to accomplish for its uses.

Thanks for the help.

Share this post


Link to post
Share on other sites
So, theoretically, if what I posted is what I need, how would I go about checking if the objects that need transparency are in my line of sight (behind my tree, for example)? and then when I call that draw function MeshAlpha(), I can just specify a new alpha value, so instead of my 1.0f do like 0.5f.


Does that sound right? Thanks for any help.

Share this post


Link to post
Share on other sites
I don't think that code sets the texture stage state the way you want to. You need to specify that you're getting your alpha value from your diffuse albedo, which is where you're setting it. I believe you do that like this:


p_d3dDevice->SetTextureStageState( D3DTSS_ALPHAOP, D3DTOP_SELECTARG1 );
p_d3dDevice->SetTextureStageState( D3DTSS_ALPHAARG1, D3DTA_DIFFUSE );


This assumes you've set the current material as your source for lighting calculations, using IDirect3DDevice9::SetRenderState( D3DRS_DIFFUSEMATERIALSOURCE, D3DMCS_MATERIAL ).

Share this post


Link to post
Share on other sites
So, what about finding out if the player model is behind the particular objects like trees, and such - to apply that transparency? I would think its something trivial, but I have no idea where to start.

-- added --
Like I posted earlier, my camera is gonna be on a fixed angle, basically like a tilted topdown view, so on the player can potentially be behind the object, so I'm just looking to find a way to 'determine' if its obstructing the view of my model and then give me an opportunity to apply my alpha to it.

Share this post


Link to post
Share on other sites
I don't have much experience with that sort of thing, but I'd imagine you'd do it by representing objects like trees as simple bounding volumes (such as a box or a square) and then doing a visibility test to see if the volume occludes the area where the player character is. So the basic algorithm would be:



-Convert object position to view space
-If object's view-space z is > 0 and < player's view-space x
-Calculate object's coverage in screen space
-If object's screen space height and width cover the player's height and width
-Make transparent

Share this post


Link to post
Share on other sites
So, basically, what you are saying is.... have two bounding volumes and do a collision test, if it is within the bounding volume's collision range, then set transparency right? Just trying to clarify...


and umm...

Quote:

-Convert object position to view space


How do you do that, per-se?

Share this post


Link to post
Share on other sites
Transform the object's world-space position by your view matrix.


D3DXVECTOR3 vObjectPosVS;
D3DXVec3TransformCoord( &vObjectPosVS, &matView, &vObjectPosWS );

Share this post


Link to post
Share on other sites
In response to your PM...

I wouldn't do a 3D collision test, I would instead do some kind of overlap test. Basically this would be like a collision test, but in 2D screen space. It would look something like this, assuming you've calculated a bounding radius for both the obstructing object and the player:



D3DXVECTOR3 vObjectPosVS, vPlayerPosVS;
D3DXVec3TransformCoord( &vObjectPosVS, &matView, &vObjectPosWS );
D3DXVec3TransformCoord( &vPlayerPosVS, &matView, &vPlayerPosWS );

if ( ( vObjectPosVS.z + fObjectRadius > 0 ) && ( vObjectPosVS.z - fObjectRadius < vPlayerPosVS.z ) )
{
D3DXVECTOR3 vPositionsVS [4];
D3DXVECTOR3 vPositionsSS [4];
D3DXVECTOR2 vObjectMaxSS;
D3DXVECTOR2 vObjectMinSS;
D3DXVECTOR2 vPlayerMaxSS;
D3DXVECTOR2 vPlayerMinSS;

// Calculate the area the object bounding volume takes up in view space
vPositionsVS[0] = D3DXVECTOR3( vObjectPosVS.x + fObjectRadius, vObjectPosVS.y, vObjectPosVS.z );
vPositionsVS[1] = D3DXVECTOR3( vObjectPosVS.x - fObjectRadius, vObjectPosVS.y, vObjectPosVS.z );
vPositionsVS[2] = D3DXVECTOR3( vObjectPosVS.x, vObjectPosVS.y + fObjectRadius, vObjectPosVS.z );
vPositionsVS[3] = D3DXVECTOR3( vObjectPosVS.x, vObjectPosVS.y - fObjectRadius, vObjectPosVS.z );

// Calculate the area the object bounding volume takes up in screen space
D3DXVec3TransformCoordArray( vPositionsSS, sizeof(D3DXVECTOR3), vPositionsVS, sizeof(D3DXVECTOR3), &matProjection, 4 );
vObjectMaxSS.x = vPositionsSS[0].x;
vObjectMinSS.x = vPositionsSS[1].x;
vObjectMaxSS.y = vPositionsSS[2].y;
vObjectMinSS.y = vPositionsSS[3].y;

// Calculate the area the player bounding volume takes up in view space
vPositionsVS[0] = D3DXVECTOR3( vPlayerPosVS.x + fPlayerRadius, vPlayerPosVS.y, vPlayerPosVS.z );
vPositionsVS[1] = D3DXVECTOR3( vPlayerPosVS.x - fPlayerRadius, vPlayerPosVS.y, vPlayerPosVS.z );
vPositionsVS[2] = D3DXVECTOR3( vPlayerPosVS.x, vPlayerPosVS.y + fPlayerRadius, vPlayerPosVS.z );
vPositionsVS[3] = D3DXVECTOR3( vPlayerPosVS.x, vPlayerPosVS.y - fPlayerRadius, vPlayerPosVS.z );

// Calculate the area the player bounding volume takes up in screen space
D3DXVec3TransformCoordArray( vPositionsSS, sizeof(D3DXVECTOR3), vPositionsVS, sizeof(D3DXVECTOR3), &matProjection, 4 );
vPlayerMaxSS.x = vPositionsSS[0].x;
vPlayerMinSS.x = vPositionsSS[1].x;
vPlayerMaxSS.y = vPositionsSS[2].y;
vPlayerMinSS.y = vPositionsSS[3].y;

// Check for overlap
if ( vObjectMaxSS.x < vPlayerMinSS.x )
return;
if ( vObjectMaxSS.y < vPlayerMinSS.y )
return;
if ( vObjectMinSS.x > vPlayerMaxSS.x )
return;
if ( vObjectMinSS.y < vPlayerMaxSS.y )
return;

// If we got here, the object is obstructing and should be made transparent

}





Also this is obvious but you wouldn't need to re-calculate the player's screen-space bounding volume for every object, I just do it there for ease of understanding.

Share this post


Link to post
Share on other sites
1) So, from my understanding, I could just store the screen-space bounding volume in my object's data structure, and when I need to perform my check utilize the necessary values. Will I be able to also store the player's information or will I always have to dynamically update that?

2) Also, the check for obstruction, would that want to be done inside my input routine? like a check after keypress? Assuming that's the case, if I have like 70 models on my screen at once (which I may use 'instancing' for - ) I would have to check every model wouldn't I? Sorry, that I seem so lost and confused.

3) fObjectRadius - is that assuming I'm using some spherical bounding box?

Thanks for any further help.

Share this post


Link to post
Share on other sites
1) The screen-space bounding volume for the objects will change every time the camera moves or the objects move, so you'll need to recalculate them. Same goes for the player, but you only need to calculate the player's volume once per frame since can use that same one to compare with all of the objects.

2) It depends on how your engine is laid out. You can either have it so it only updates when the camera moves or an object moves, or you can just do it every frame since it's very likely the camera will be moving most of the frames. And yes, you'd have to check for every model. When you're dealing with lots of models, acceleration structures like hierarchal bounding volumes (BVH's) and quad-trees can help speed up the process from O(N) to O(logN). However these are beyond my expertise.

3) Yes, this assumes you've figured out a bounding sphere and the object's position is at the center. You can either do this yourself by finding the max distance from the object's position to a vertex, or you can use D3DXComputeBoundingSphere.

Share this post


Link to post
Share on other sites
Oh wow, never really messed with the D3DX Bounding Volume functions, but looks easy as cake.

Assuming pMesh is my Mesh:


// Lock the Vertex Buffer
if(SUCCEEDED(pMesh->LockVertexBuffer(D3DLOCK_READONLY, (BYTE**)&Ptr)))
{
// Computer Bounding Sphere Radius
D3DXComputeBoundingSphere((void*)Ptr, pMesh->GetNumVertices(), pMesh->GetFVF(), &D3DXVECTOR3(0.0f, 0.0f, 0.0f), &fObjectRadius);
// Unlock the Vertex Buffer
pMesh->UnlockVertexBuffer();
}




seems easy enough. :) I'll only have the compute that in my initlizations once, because radius won't ever change - just location. I think I'll end up storing my screen-space bounding volumes inside the data structure for my objects/players move functions, some quick update routine.

In regards to questions 2) I don't think I'm going to worry that much, I'm going to do some instancing since I'll do like several trees and such - for particular levels, but I'm going to go with the old tedius RPG-style loading, like Secret of Mana did, where you have the area, and can zone in and out - unless it becomes to unpheasible - then when I learn how to handle quadtree algorithms, I may add that and just load the entire world. We'll see how that goes.

Anyhow, I think I've got everything I need so far and appreciate the help MJP. -as always, lol.

Share this post


Link to post
Share on other sites
Two quick things:

1. You want to use pMesh->GetNumBytesPerVertex instead of pMesh->GetFVF for the third parameter, since the function needs to know how "big" each vertex is.

2. The radius that function returns to you is with respect to pCenter, which means the actual radius you want to use is calculated like this:


D3DXVECTOR3 vCenter;
D3DXComputeBoundingSphere((void*)Ptr, pMesh->GetNumVertices(), pMesh->GetNumBytesPerVertex(), &vCenter, &fObjectRadius);
fObjectRadius = D3DXVec3Length(&vCenter) + fObjectRadius;

Share this post


Link to post
Share on other sites
Quote:

excerpt from http://www.toymaker.info/Games/html/load_x_simply.html

When rendering our subsets if any of them are transparent (contain alpha information) you should render them last after rendering the ones without alpha. This is required for the blending to work correctly. So you could have two loops, the first one renders all subsets where the material has a diffuse alpha component of 1.0f (no transparency) and the second one renders all those with an alpha component less than 1.0f (some transparency).


Which would explain your correcting me, what I had represented what the excerpt shows, if the x-file had a transparency to it previously, it would be handled accordingly, but when you are applying a transparency to an originally non-transparent item, I assume you do it the way you explained earlier in previous posts.

Quote:

MJP

I don't think that code sets the texture stage state the way you want to. You need to specify that you're getting your alpha value from your diffuse albedo, which is where you're setting it. I believe you do that like this:


p_d3dDevice->SetTextureStageState( D3DTSS_ALPHAOP, D3DTOP_SELECTARG1 );
p_d3dDevice->SetTextureStageState( D3DTSS_ALPHAARG1, D3DTA_DIFFUSE );


This assumes you've set the current material as your source for lighting calculations, using IDirect3DDevice9::SetRenderState( D3DRS_DIFFUSEMATERIALSOURCE, D3DMCS_MATERIAL ).


Anyhow, I'm going to ahead and work on this a bit more. I should have something phesible put together by tommorow.

[Edited by - QuinnJohns on April 3, 2008 10:24:48 PM]

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement