Index | FAQ | Search | Memberlist | Usergroups | Profile | Log in to check your private messages | Log in | Register

Tutorial: Adding Alpha Transparency to stock GLQUAKE Goto page Previous 1, 2

| Inside3d Forums Forum Index -> Programming Tutorials

View previous topic :: View next topic
Author | Message
--- | ---
Baker Joined: 14 Mar 2006 Posts: 1538 |

Posted: Sun Nov 30, 2008 12:10 am Post subject: |

goldenboy wrote:
I think I remember transparent water in software in FTE - dunno if it also does alpha entities. I should test. :-E

I've heard that FTE uses 24 bit color in software mode. If true, the issue of the constrained limitation of 256 colors for the whole window doesn't come into play.

Back to top |

Tomaz Joined: 05 Nov 2004 Posts: 49 |

Posted: Mon Dec 01, 2008 1:32 pm Post subject: |

This is like the 5:th tutorial from you that i read that shows a feature and list a few engines that supports it, and also the 5:th tutorial that doesnt list TomazQuake as one of the engines supporting it. Nice tutorial, but why do I get the feeling you're not really sure what you're doing?
1) You send a 2 then the transluceny value, then you read it into a temp which isnt used, why not just not send it?
2) Why are you using floats when a byte is more than enough?
0-255, just do / 255.0f;
3) So now you have support for transparent object, but where is the alpha sorter? Sure the objects will be transparent, but 99.9% of the time there will be objects in behind the transparent object that wont be rendered.
Here is why:
Lets use a window in a map as the transparent object.
Whenever the window is rendered it also writes to the z-buffer. If this is rendered BEFORE an object behind the window, lets say a monster, that monster wont be visible through the window because the 3d card will reject it isnce its to far away in the z-buffer.
The sollution, always render opaque objects first ( thatd be the ones not being transparent ) and then render all transparent object SORTED from back to front. This will work fine for things like a window, but for object with a more complex geometry it might not be enough to sort the object from back to front, one might have sort every triangle from back to front ( which i think DP does, or at least did at some point ).
TomazQuake didnt go that far, one thing I DID do tho was fixing so the particle system works with water ( which isnt covered here either ) which does a similar thing. There i sort all the particles as being either in front or behind the water plane. So the render order is, Particles behind water, water, particles in front of water.
Enough from me in this thread, im gonna comment a few more of your tutorials tho.

Back to top |

r00k Joined: 13 Nov 2004 Posts: 483 |

Posted: Mon Dec 01, 2008 9:59 pm Post subject: |

Code:
void SortEntitiesByTransparency (void) { int i, j; entity_t *tmp; for (i = 0 ; i < cl_numvisedicts ; i++)
{
if (cl_visedicts[i]->transparency < 1 && cl_visedicts[i]->transparency > 0)
{
for (j = cl_numvisedicts - 1 ; j > i ; j--)
{
// if not transparent, exchange with transparent
if (cl_visedicts[j]->transparency == 1)
{
tmp = cl_visedicts[i];
cl_visedicts[i] = cl_visedicts[j];
cl_visedicts[j] = tmp;
break;
}
else
continue;
}
if (j == i)
return;
}
}
}

Back to top |

Baker Joined: 14 Mar 2006 Posts: 1538 |

Posted: Mon Dec 01, 2008 10:36 pm Post subject: |

Tomaz wrote:
Whenever the window is rendered it also writes to the z-buffer. If this is rendered BEFORE an object behind the window, lets say a monster, that monster wont be visible through the window because the 3d card will reject it isnce its to far away in the z-buffer.

Ah! I noticed that but didn't know why that was happening. I wasn't seeing monsters behind windows, etc.
@Rook: where should have that called from?
Edit = nevermind, got it

Code:
void R_DrawEntitiesOnList (void) { int i; if (!r_drawentities.value) return;
SortEntitiesByTransparency ();

Edit #2 = Cool! Much better.

Back to top |

mh Joined: 12 Jan 2008 Posts: 910 |

Posted: Sat Aug 22, 2009 11:23 pm Post subject: |

r00k wrote:

Code:
void SortEntitiesByTransparency (void) { int i, j; entity_t *tmp; for (i = 0 ; i < cl_numvisedicts ; i++)
{
if (cl_visedicts[i]->transparency < 1 && cl_visedicts[i]->transparency > 0)
{
for (j = cl_numvisedicts - 1 ; j > i ; j--)
{
// if not transparent, exchange with transparent
if (cl_visedicts[j]->transparency == 1)
{
tmp = cl_visedicts[i];
cl_visedicts[i] = cl_visedicts[j];
cl_visedicts[j] = tmp;
break;
}
else
continue;
}
if (j == i)
return;
}
}
}

No, that's gonna group the entities, but it won't sort them back to front. Not to mention being the WRONG sorting algorithm. You need to check entities at the point at which they're added to the cl_visedicts array, if they have transparency then add them to a second cl_transedicts array, then do something like this:

Code:
int D3D_EntityDepthCompare (const void *a, const void *b) { entity_t *enta = *((entity_t **) a); entity_t *entb = *((entity_t **) b); // sort back to front
if (enta->dist > entb->dist)
return 1;
else if (enta->dist < entb->dist)
return -1;
else return 0;
}
void D3D_DrawTranslucentEntities (void)
{
if (!r_drawentities.value) return;
if (!d3d_RenderDef.numtransedicts) return;
// if there's only one then the list is already sorted!
if (d3d_RenderDef.numtransedicts > 1)
{
// evaluate distances
for (int i = 0; i < d3d_RenderDef.numtransedicts; i++)
{
entity_t *ent = d3d_RenderDef.transedicts[i];
// set distance from viewer - no need to sqrt them as the order will be the same
// (fixme - should we, and then subtract a radius?)
ent->dist = (ent->origin[0] - r_origin[0]) * (ent->origin[0] - r_origin[0]) +
(ent->origin[1] - r_origin[1]) * (ent->origin[1] - r_origin[1]) +
(ent->origin[2] - r_origin[2]) * (ent->origin[2] - r_origin[2]);
}
if (d3d_RenderDef.numtransedicts == 2)
{
// trivial case - 2 entities
if (d3d_RenderDef.transedicts[0]->dist < d3d_RenderDef.transedicts[1]->dist)
{
// reorder correctly
entity_t *tmp = d3d_RenderDef.transedicts[1];
d3d_RenderDef.transedicts[1] = d3d_RenderDef.transedicts[0];
d3d_RenderDef.transedicts[0] = tmp;
}
}
else
{
// general case - depth sort the transedicts from back to front
qsort ((void *) d3d_RenderDef.transedicts, d3d_RenderDef.numtransedicts, sizeof (entity_t *), D3D_EntityDepthCompare);
}
}
// global state for translucent ents - we're drawing back to front so we can write to Z
D3D_EnableAlphaBlend (D3DBLENDOP_ADD, D3DBLEND_SRCALPHA, D3DBLEND_INVSRCALPHA, false);
// now draw 'em
// we can't state-batch these as they need correct ordering so we'll just live with the state changes...
for (int i = 0; i < d3d_RenderDef.numtransedicts; i++)
{
d3d_RenderDef.currententity = d3d_RenderDef.transedicts[i];
if (d3d_RenderDef.currententity->model->type == mod_sprite)
D3D_DrawSpriteModel (d3d_RenderDef.currententity);
else if (d3d_RenderDef.currententity->model->type == mod_alias)
D3D_DrawTranslucentAliasModel (d3d_RenderDef.currententity);
else if (d3d_RenderDef.currententity->model->type == mod_brush)
R_DrawBrushModel (d3d_RenderDef.currententity);
else
{
// just print a warning
Con_DPrintf
(
"Unknown model type %i for %s\n",
d3d_RenderDef.currententity->model->type,
d3d_RenderDef.currententity->model->name
);
}
}
// take down global state
D3D_DisableAlphaBlend ();
}

You could also accomplish similar with a Mod_PointInLeaf, storing translucent ents in leafs, then doing a BSP tree walk, but this way is much simpler overall, especially as there will (hopefully!) only be a small handful of translucent ents in any given scene. qsort speeds are comparable to a BSP walk even for all surfs in the view anyway, so best not to even go there.
Even then it won't handle cases where alpha ents are overlapping, but that's probably getting into too much complexity (especially if they have different model types).
_________________
DirectQ Engine - New release 1.8.666a, 9th August 2010
MHQuake Blog (General)
Direct3D 8 Quake Engines

Back to top |

reckless Joined: 24 Jan 2008 Posts: 390 Location: inside tha debugger |

Posted: Sat Aug 22, 2009 11:35 pm Post subject: |

hmm strange that one seems kinda familiar ah aye

Code:
// sort draworder by depth int R_DepthSortSprites(const void *arg1, const void *arg2) { draworder_t *pOrder1, *pOrder2; static int diff;
pOrder1 = (draworder_t *) arg1;
pOrder2 = (draworder_t *) arg2;
if (pOrder1->depth > pOrder2->depth)
{
diff = -1;
}
else if (pOrder1->depth < pOrder2->depth)
{
diff = 1;
}
else
{
diff = 0;
}
return diff;
}

Code:
typedef struct draworder_s { float depth; int order; } draworder_t;

Code:
void R_DrawSpritesOnList (void) { int i; entity_t *tempentity; draworder_t sprite_order[MAX_EDICTS];
vec3_t temp_org = {0, 0, 0};
vec3_t sprite_org;
if (!r_drawentities.value) return;
// make new list of ents by depth and current order in list
for (i=0 ; i<cl_numvisedicts ; i++)
{
tempentity = cl_visedicts[i];
VectorCopy(tempentity->origin, sprite_org);
VectorSubtract(sprite_org, r_origin, temp_org);
sprite_order[i].depth = Length(temp_org);
sprite_order[i].order = i;
}
// sort this new list by depth, back to front
qsort(sprite_order, cl_numvisedicts, sizeof(draworder_t), R_DepthSortSprites);
// classic quake only has a handful of sprites: light globes, bubbles and explosions.
// hipnotic added a few more, but they looked ghastly even back in the late 90s, so
// we'll just pretend they never happened. the main ones we want to deal with are
// the globes and bubbles. sprite replacement is handled in the drawing routine.
for (i=0 ; i<cl_numvisedicts ; i++)
{
currententity = cl_visedicts[ sprite_order[i].order ];
// not an sprite model
if (currententity->model->type != mod_sprite) continue;
// occluded during previous pass
if (currententity->occluded) continue;
R_DrawSpriteModel (currententity);
}
}

could probably be used for the same ?

Back to top |

mh Joined: 12 Jan 2008 Posts: 910 |

Posted: Sun Aug 23, 2009 10:53 am Post subject: |

Kinda, but it's not really calculating the distance correctly. Check my dist calc above, and remember that you don't need to sqrt the result cos if x > y then sqrt(x) also > sqrt (y). _________________ DirectQ Engine - New release 1.8.666a, 9th August 2010
MHQuake Blog (General)
Direct3D 8 Quake Engines

Back to top |

reckless Joined: 24 Jan 2008 Posts: 390 Location: inside tha debugger |

Posted: Sun Aug 23, 2009 11:27 am Post subject: |

noticed hmm lemme see what i can cook up.

Back to top |

Lardarse Joined: 05 Nov 2005 Posts: 243 Location: Bristol, UK |

Posted: Sun Aug 23, 2009 9:10 pm Post subject: |

mh wrote:
Kinda, but it's not really calculating the distance correctly. Check my dist calc above, and remember that you don't need to sqrt the result cos if x > y then sqrt(x) also > sqrt (y).

I think that there are exceptions when both are less than 1, but I might be wrong...
_________________
<ekiM> Son, you're writing data structures your CPU can't cache.

Back to top |

Team Xlink Joined: 25 Jun 2009 Posts: 320 |

Posted: Sun Aug 23, 2009 9:13 pm Post subject: |

So does this mean that this tutorial in the first post doesn't work right? _________________

Anonymous wrote:
if it works, it works. if it doesn't, HAHAHA!

Back to top |

Electro Joined: 29 Dec 2004 Posts: 241 Location: Brisbane, Australia |

Posted: Sun Aug 23, 2009 9:22 pm Post subject: |

Team Xlink: correct _________________ Unit reporting! http://www.bendarling.net/

Back to top |

Team Xlink Joined: 25 Jun 2009 Posts: 320 |

Posted: Sun Aug 23, 2009 10:17 pm Post subject: |

Electro wrote:
Team Xlink: correct

Time to go dig through my source code to remove it or fix it then.
_________________

Anonymous wrote:
if it works, it works. if it doesn't, HAHAHA!

Back to top |

reckless Joined: 24 Jan 2008 Posts: 390 Location: inside tha debugger |

Posted: Sun Sep 20, 2009 2:43 am Post subject: |

Code:
// if there's only one then the list is already sorted! if (cl_numvisedicts > 1) { // evaluate distances for (i = 0; i < cl_numvisedicts; i++)
{
entity_t *ent = cl_visedicts[i];
// set distance from viewer - no need to sqrt them as the order will be the same
// (fixme - should we, and then subtract a radius?)
ent->alphadist = (ent->origin[0] - r_origin[0]) * (ent->origin[0] - r_origin[0]) + (ent->origin[1] - r_origin[1]) * (ent->origin[1] - r_origin[1]) + (ent->origin[2] - r_origin[2]) * (ent->origin[2] - r_origin[2]);
}
if (cl_numvisedicts == 2)
{
// trivial case - 2 entities
if (cl_visedicts[0]->alphadist < cl_visedicts[1]->alphadist)
{
entity_t *tmpent = cl_visedicts[1];
// reorder correctly
cl_visedicts[1] = cl_visedicts[0];
cl_visedicts[0] = tmpent;
}
}
else
{
// general case - depth sort the transedicts from back to front
qsort ((void *) cl_visedicts, cl_numvisedicts, sizeof (entity_t *), R_DepthSortEntities);
}
}
//Enable alpha blending
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
/* your drawing functions here */
//Disable alpha blending
glDisable(GL_BLEND);

seems to work. not sure if i need to depthcheck first ?
add float alphadist; to entity_t struct.

Back to top |

Display posts from previous:

| Inside3d Forums Forum Index -> Programming Tutorials | All times are GMT Goto page Previous 1, 2
Page 2 of 2

Jump to:

You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum

Powered by phpBB © 2004 phpBB Group