Game Development Community

Translucency Problem

by Vlad Ts · in Torque Game Engine · 10/18/2005 (6:04 am) · 9 replies

Hello Community!

Spending two weeks with searching solution of Translucency Support in Torque and wanna share our thoughts with you.

So, problem: not correct support of Translucency Part rendering inside scene. Example: we have model (mesh of soldier) with hard hat and its view glass is translucent as it should be in real world.

While prerendering phase Torque builds tree for correct rendering of those parts like our view glass. And what we have as a result - something terribly.
We try to solve this problem by exploring forum and asking people, but we did not achived no results. Some pople in community belives that such problem is common for all engines,
some did not mind on that, because of low use translucency in their projects, some belives that "SORT" before model name would fix everything. We wanna devote to discussion about
this functionality and our conclusions about them.

Then we start exploring problem by checking sources, and debug them step by step. And get interesting thing. When we got this engine first question to comunity was: where can we
find some kind of documentation how start new project with torque support, or get detail explonation about removing everythig unusable from demo. Answer was - this is too hard and
we would not spend our time for producing such doc, because our engine is AAA class. WE were in deep shock, but now we inderstand that real problem in sources, they are so unreadable
in some places that it would be hard even describe what that code do.

After exploring part of engine that implements rendering process, we got some reasonable questions for developers

Why are you using such "interesting" way of rendering except of using simple and effective methods of rendering translucenct parts or mesh?
(Ofcorse you can say that in acient times when you start developing this engine video accelerators using Z-buffer not so effective for
this problem, but as we understand on our experience that problem was with realy acient video cards, but not now)

Why not using simplest and most effective way of rendering scene ? :
1. Render all solid polygons with depth test enable and depth masks on
2. Render all transparent polygons with depth test enable and depth mask off
3. Render FX if it neaded.

When we search for 3D engine first thing that we explore was - all supported features, and Translucency was included in that list. But now we have
1 month of headache because of that AAA product (Single Mode Applications, Animation Blending, Translucency, Not enought documentations, No project
base for development, Unreadable code and this is not full list of problems).

So this is it. What are you thinking about that people?. If someone has a solution for translucency problem please share sources with people in community.
As for us, we starts to rewriting rendering code, for implementing more optimal way of rendering.


P.S. Sorry for my terrible english, not enought practice.

#1
10/19/2005 (1:40 am)
Hi,

I dont see any problems with torques implementation of translucencies so far. Even in your solution you would have to SORT the transparent polygons you send to the renderer. That is because you still dont have any possibility to tell which translucent polygon is in front of the other as you dont write any z-values. Just imagine a translucent cube where the backfaces are drawn in front of the frontfaces.

From my understanding Torque renders translucent objects like this (i might be wrong tho)

1. Render all solid polygons with depth test enable and depth masks on
2. SORT all translucent polygons in a bsp tree so that they are drawn from back to front
3. Render all translucent polygons from back to front (using the BSP tree) with depth test on and depth mask off

The only technique i know of that uses a pure Z-Buffer approach is Depth-Peeling. But that is a Pixel and Vertex Shader technique and thus isnt TGE.

On a side Note: There is a sweet article about Z-Sorting and transparencies here :)

Florian
#2
10/19/2005 (2:14 am)
There are definitely issues with Torque's transparency sorting... Take a look at a tree in the starter.fps and you will see Transparency issues. If you place a bunch of those trees together (so the leaves are all touching each other and jumbled together) you will start to get some nasty z-fighting going on.

So, to re-cap, there seem to be two major transparency issues that I have seen and can be reproduced 100% of the time. The first issue seems to be contained to when you have transparent polygons from different dts shapes intersecting each other (such as the leaves from multiple trees all intersecting) and causing the aforementioned z-fighting. The second issue is when you have transparent planes intersecting each other within a dts shape (such as leaves within the tree model iteself) which cause sorting issues (parts of one polygon will be incorrectly rendered before parts of another polygon).

These are definitely known issues and there are no workarounds to my knowledge (no, ::SORT does not work and 'proper' modeling techniques are impervious!) These issues are present in any game engine that I know of as they are virtually impossible (save from cutting up your model in ridiculously small polygons) to correct...

Ben Garney has said that he has implemented a stand-alone sorting algorithm for his Forest Pack, which is all we would need for our game... assuming it works properly (it will still need to be tied to the Torque sorting algorithms, so it may still fall short). Other than that, I do not know of any fixes... Please prove me wrong!

Take care,

Stephane
#3
10/19/2005 (3:19 am)
Hi Stephane,

I never said that the solution in Torque doesnt have any issues, i said that i dont see a problem there.

I could think of 3 ways to remove the flickering.

1. cutting and sorting polygons during runtime (very slow)
2. Depth Peeling (requires several readbacks from GFX buffer + Pixel Shader = slow/impossible on old graphic cards)
3. glAlphaFunc with Z-Writing on (only works for faces that are either 100% visible or 100% invisble)

For your Tree example i think you could implement a custom SceneObject that uses glAlphaFunc but that would introduce rather sharp edges on your leafes. The only artifacts you will see there are caused by Z-Buffer accuracy.

But i think that with smart art design and with smart placing of objects you can reduce artifacts to a minimum. In other words: "Programmer guy says its an art problem and art guy says that its a software problem"

Florian
#4
10/19/2005 (5:50 am)
Florian Ross - nothing personaly, but did you ever try to think about transparency and why torque writes such algo for it ?
1. cutting and sorting polygons during runtime - very slow, yes You right
2. Depth Peeling (requires several readbacks from GFX buffer + Pixel Shader = slow/impossible on old graphic cards) - who talks about shaders?
3. glAlphaFunc with Z-Writing on (only works for faces that are either 100% visible or 100% invisble) - here you are wrong little bit.

We work with 3D Graphics near by 8 years, and using OpenGL in most application, unfortunatly all our experience was not enought for writing 3D Engine in 1 month, thats because we now using Torque. In all applications that we write and which use any king of transparency we use simple algo:

1. render solid part of scene (this do not need any sorting just one pass through all scene objects and render their solid faces) - this part also renders polygons with alpha chanel, there is no problem in them, accelerator (even Voodoo) writes polygon in correct way, it writes only wisible part, where alpha = 0 (not transparent)

2. render polygons with transparency and alpha+transparency(second pass through all objects, no sorting needs, I underline - NO SORTING), we turning off depht mask, and use blending and depth buffer

Result is exactly what should have after rendering such scene for example with raytraicing algo in 3D MAX. This is most powerfull and easiest way for getting right picture. And I can not imagine that any Game Engine has such problem. So problem still open, and it is sounds like - Would it be code patch for Torque Rendering Phase for supporting normal transparency?

"with smart art design" and "smart placing of objects" - those things are not acceptable, if we writing good product. This is for personse who did not care about customers and they level of product.
#5
10/19/2005 (5:51 am)
//this is example of our code (from our applications)

//rendering
//Draw Solid Polygons
lpTempElement = lpSceneObjects;
while (lpTempElement)
{
LPTSCENEOBJECT lpSceneObject = (LPTSCENEOBJECT)lpTempElement->lpObject;
if (lpSceneObject) lpSceneObject->Draw(DRAW_TYPE_SOLID);
lpTempElement = lpTempElement->lpNextElement;
}

//Draw List With Effects Objects
lpTempElement = lpSceneObjects;
while (lpTempElement)
{
LPTSCENEOBJECT lpSceneObject = (LPTSCENEOBJECT)lpTempElement->lpObject;
if (lpSceneObject)
{
lpSceneObject->Draw(DRAW_TYPE_TRANSPARENT);
lpSceneObject->Draw(DRAW_TYPE_EFFECTS);
}
lpTempElement = lpTempElement->lpNextElement;
}


//cntainer for graphics
void TPolygonalObject::Draw( DWORD dwDrawType )
{
if (dwDrawType == DRAW_TYPE_EFFECTS) return;

if ( lpdmMeshData == NULL ) return;
LPTMESHMODULE mesh = lpdmMeshData;

glPushMatrix( );

CalculateMatrix();

if ( dwDrawType == DRAW_TYPE_TRANSPARENT )
{
glEnable( GL_BLEND );
glBlendFunc( GL_SRC_ALPHA, GL_ONE );
glDepthMask( GL_FALSE );
glDisable( GL_CULL_FACE );
}


for (DWORD i=0; idwNumOfSolidTriangles; i++ )
{

if ( mesh->lpMaterials[ mesh->lpSTri[i].mat_indx ].color.a != 1.0f && dwDrawType == DRAW_TYPE_SOLID ) continue;
if ( mesh->lpMaterials[ mesh->lpSTri[i].mat_indx ].color.a == 1.0f && dwDrawType == DRAW_TYPE_TRANSPARENT ) continue;

//set mesh color
glColor4f( mesh->lpMaterials[ mesh->lpSTri[i].mat_indx ].color.r,
mesh->lpMaterials[ mesh->lpSTri[i].mat_indx ].color.g,
mesh->lpMaterials[ mesh->lpSTri[i].mat_indx ].color.b,
mesh->lpMaterials[ mesh->lpSTri[i].mat_indx ].color.a );


//chack if there is a uv map
int uv_id = mesh->lpMaterials[ mesh->lpSTri[i].mat_indx ].uvmap_id;
if ( uv_id != -1 )
{
glEnable( GL_TEXTURE_2D );
glBindTexture( GL_TEXTURE_2D, mesh->lpMaterials[ mesh->lpSTri[i].mat_indx ].img_id );
}

if (!mesh->lpMaterials[ mesh->lpSTri[i].mat_indx ].fSmooth) glNormal3fv( (float*)&mesh->lpNormal[ i ] );

glBegin( GL_TRIANGLES );

//Smooth Normal
if (mesh->lpMaterials[ mesh->lpSTri[i].mat_indx ].fSmooth)
{
glNormal3fv( (float*)&mesh->lpSmoothNormal[ (mesh->lpSTri[i]).vert_indx[0] ] );
//UV Map ID
if ( uv_id != -1 )
glTexCoord2fv( (float*)&mesh->lpUVMap[ uv_id ].lpUV[ i*3+0 ] );
}
//Vertex
glVertex3fv( (float*)&mesh->lpVertex[ mesh->lpSTri[i].vert_indx[0] ] );



//Smooth Normal
if (mesh->lpMaterials[ mesh->lpSTri[i].mat_indx ].fSmooth)
{
glNormal3fv( (float*)&mesh->lpSmoothNormal[ (mesh->lpSTri[i]).vert_indx[1] ] );
//UV Map ID
if ( uv_id != -1 )
glTexCoord2fv( (float*)&mesh->lpUVMap[ uv_id ].lpUV[ i*3+1 ] );
}
//Vertex
glVertex3fv( (float*)&mesh->lpVertex[ mesh->lpSTri[i].vert_indx[1] ] );



//Smooth Normal
if (mesh->lpMaterials[ mesh->lpSTri[i].mat_indx ].fSmooth)
{
glNormal3fv( (float*)&mesh->lpSmoothNormal[ (mesh->lpSTri[i]).vert_indx[2] ] );
//UV Map ID
if ( uv_id != -1 )
glTexCoord2fv( (float*)&mesh->lpUVMap[ uv_id ].lpUV[ i*3+2 ] );
}
//Vertex
glVertex3fv( (float*)&mesh->lpVertex[ mesh->lpSTri[i].vert_indx[2] ] );

glEnd( );

glDisable( GL_TEXTURE_2D );

}

glDisable( GL_BLEND );
glDepthMask( GL_TRUE );
glEnable( GL_CULL_FACE );
glDisable( GL_TEXTURE_2D );
glPopMatrix( );

}



This is just an example not optimal, but it works and it produce correct picture. Possible improvements would be presorting of mesh data and group data for using polygons list for rendering.
#6
10/19/2005 (7:17 am)
I actually did think about transparencies (mostly for TSE)

a simple rule of the blending equation is that the order in which you blend is important.

in math: blending A + B is not the same than blending B + A

you HAVE to draw faces from back to front so simulate the correct order in which light passes the various surfaces. Even a raytracer does that.

Let me rephrase what you are doing:

Quote:
1. render solid part of scene (this do not need any sorting just one pass through all scene objects and render their solid faces) - this part also renders polygons with alpha chanel, there is no problem in them, accelerator (even Voodoo) writes polygon in correct way, it writes only wisible part, where alpha = 0 (not transparent)

That is obvious. Writing solid objects as you would with every solid object. The second part is interesting. You say that you only write fully visible fragments (fragments with an alpha value of 1.0f)

so basicely you write:
glAlphaFunc (GL_EQUAL, 1.0f);
to get rid of all fragments with an alpha value less than 1.0f

up until now you have a completely valid Z-Buffer which you use for the second step:

Quote:
2. render polygons with transparency and alpha+transparency(second pass through all objects, no sorting needs, I underline - NO SORTING), we turning off depht mask, and use blending and depth buffer

by turning off depth mask you dont write any Z-Values to the depth buffer, which is correct. By using Depth-Testing you dont write over any existing objects that have a lower Z-Value. (i.e. your character standing before a window). that is correct too.

but if you could just render polygons without sorting and they come up in the correct order then we wouldnt needing any Z-Buffer at all, wouldnt we? So my point is that if you dont sort your transparent polygons you will get incorrect results from your blending equation.

next topic:

Quote:
1. cutting and sorting polygons during runtime - very slow, yes You right
2. Depth Peeling (requires several readbacks from GFX buffer + Pixel Shader = slow/impossible on old graphic cards) - who talks about shaders?
3. glAlphaFunc with Z-Writing on (only works for faces that are either 100% visible or 100% invisble) - here you are wrong little bit.

those were possibilities of how to get correctly sorted transparencies. That said, let me answer:

2. i was talking about shaders as you would need to use them for Depth Peeling
3. i didnt quite type what i was thinking in this, so you are correct to correct me. Should be:
"only works if the desired result is either a 0.0f or 1.0f alpha fragment. Doesnt work for semi-transparent fragments"

As for my part i think that the code you posted is rather unreadable and a good example why comments might me a bad thing. But that might just be my personal intention.

If i'm really that far off then please correct me. Could be that i'm wrong on this. but i doubt it.

Florian
#7
10/19/2005 (11:41 am)
I must admit the following that your technique works in one special case:

If you are only writing 1 transparent fragment per pixel, then you only blend with solid geometry which has been drawn in the first pass. In this case your solution is right. But as soon as you have to blend a material with a blended material you have to ensure the correct order in which you draw the polygons.

its nothing personal, really. i just think that your solution has a quirk. Please prove me wrong if i am. Maybe i just forgot to set one switch

Florian
#8
03/26/2007 (12:18 pm)
I think it's a serious problem in Torque that I didn't see in another engines.

My game have a forest and it's painful to make everything looks right.
#9
03/26/2007 (4:29 pm)
I have found if you make your bounding box just a tinny bit larger then your tree tunks, (and exclude as much of the transparent texture as possible), one may achieve a descent looking 'forest' of trees. Of course this will cause trees at the edges of the players vision to POP out of view, but i dont think its as much eyesore as tree leafs that do not sort correctly..