Transparency on Moving Entities (Quake2)

Discuss programming topics for the various GPL'd game engine sources.
Post Reply
jitspoe
Posts: 217
Joined: Mon Jan 17, 2005 5:27 am

Transparency on Moving Entities (Quake2)

Post by jitspoe »

Surely somebody has already fixed this and can save me the effort... If you use a transparent brush on something like a door, the transparent polygons stay in place while the door moves. Anybody know of some code or an engine that fixes this?
Spike
Posts: 2914
Joined: Fri Nov 05, 2004 3:12 am
Location: UK
Contact:

Re: Transparency on Moving Entities (Quake2)

Post by Spike »

transparent polys are added to some separate list when drawn. just the polygons, so they loose all context regarding their owning entity. which means they don't have the right matrix and can't move/rotate.

fte builds batch lists, ordered by blend mode and grouped by texture+entity. each batch retains the context of the render-entity thus any origin/angles/alpha/colormod/light directions/etc all carry through to the polys that need them.
the code is quite different from vanilla q2 though, so I don't know how useful knowing that is to you.

either build a per-entity list instead of a single global list for transparent surfaces, or just store a pointer to the owning entity with each surface and update the modelview matrix if that rentity pointer changes from one surface to the next.
Barnes
Posts: 232
Joined: Thu Dec 24, 2009 2:26 pm
Location: Russia, Moscow
Contact:

Re: Transparency on Moving Entities (Quake2)

Post by Barnes »

try this

Code: Select all

void R_DrawAlphaPoly(void)
{
	msurface_t *s;

	//
	// go back to the world matrix
	//

	qglLoadMatrixf(r_world_matrix);
	qglDepthMask(0);
	
	for (s = r_alpha_surfaces; s; s = s->texturechain) {

		if (s->ent)
			R_RotateForLightEntity(s->ent);

		if (s->texinfo->flags & SURF_TRANS33) 
			shadelight_surface[3] = 0.33;
		else	
		if (s->texinfo->flags & SURF_TRANS66) 
			shadelight_surface[3] = 0.66;
		else
			shadelight_surface[3] = 1.0;
		

		if (s->flags & SURF_DRAWTURB)
			R_DrawWaterPolygons(s);
		else if (s->texinfo->flags & SURF_FLOWING)
			DrawGLFlowingPolyGLSL(s);
		else
			DrawGLPolyGLSL(s);

	}

	qglColor4f(1, 1, 1, 1);
	qglDepthMask(1);
	r_alpha_surfaces = NULL;
}
jitspoe
Posts: 217
Joined: Mon Jan 17, 2005 5:27 am

Re: Transparency on Moving Entities (Quake2)

Post by jitspoe »

Barnes wrote:try this
I guess that would require adding an ent pointer to all the surfaces... not sure how much memory overhead that would have, but it may be the easiest solution.
Knightmare
Posts: 63
Joined: Thu Feb 09, 2012 1:55 am

Re: Transparency on Moving Entities (Quake2)

Post by Knightmare »

This is one of the oldest Q2 rendering bugs that has a fix available. I think it was Quake2Max that first addressed it back in 2002. Hard to believe that R1GL still doesn't have this fixed.

Be sure to load the world matrix before caling R_RotateForEntity() for each surface, and again after the last one, or it will end up moving the first-person weapon model, too.

These bmodel alpha surfs aren't depth-sorted from traversing the BSP tree, so they will occlude others behind them (due to being stuffed at the front of the alpha chain). Various attempts to depth sort them failed, so I ended up just disabling the depth mask when rendering them.

You can also use this surface ent pointer to enable animated textures on both bmodel and world alpha surfaces (see my unofficial v3.24 patch source). The added pointer is only 4 bytes per surface, and the memory use increase is negligible compared to v3.20.
Knightmare
Posts: 63
Joined: Thu Feb 09, 2012 1:55 am

Re: Transparency on Moving Entities (Quake2)

Post by Knightmare »

Here's an except of the changes I made for moving and animating trans faces in Q2's ref_gl.

I tried to make similar changes to ref_soft recently, but the results were disastrous. It's very very difficult to change any functionality in that code.

Definition of msurface_s in gl_model.h:

Code: Select all

typedef struct msurface_s
{
	.
	.
	.
	entity_t	*entity;		// Knightmare- added entity pointer
} msurface_t;

Top of gl_rsurf.c:

Code: Select all

int			r_worldframe;		// Knightmare- added for trans animations
Modified R_TextureAnimation (takes surface as parameter instead of texinfo):

Code: Select all

image_t *R_TextureAnimation (msurface_t *surf)
{
	int			c, frame;
	mtexinfo_t	*tex = surf->texinfo;

	if (!tex->next)
		return tex->image;

	if (tex->flags & (SURF_TRANS33|SURF_TRANS66)) {
		if (!surf->entity)
			frame = r_worldframe; 	// use worldspawn frame
		else
			frame = surf->entity->frame;
	}
	else
		frame = currententity->frame;

	c = frame % tex->numframes;
	while (c)
	{
		tex = tex->next;
		c--;
	}

	return tex->image;
}
R_DrawInlineBmodel:

Code: Select all

	.
	.
	.
	qboolean	duplicate;	// Knightmare added
	.
	.
	.
	for (i=0 ; i<currentmodel->nummodelsurfaces ; i++, psurf++)
	{
		.
		.
		.
		// draw the polygon
		if (((psurf->flags & SURF_PLANEBACK) && (dot < -BACKFACE_EPSILON)) ||
			(!(psurf->flags & SURF_PLANEBACK) && (dot > BACKFACE_EPSILON)))
		{
			psurf->entity = NULL;	// make sure this is NULL
			if ( psurf->texinfo->flags & SURF_SKY )
				continue;
			if ( psurf->texinfo->flags & (SURF_TRANS33|SURF_TRANS66) )
			{
				// add to the translucent chain
				// if bmodel is used by multiple entities, adding surface
				// to linked list more than once would result in an infinite loop
				duplicate = false;
				for (s = r_alpha_surfaces; s; s = s->texturechain)
					if (s == psurf)
					{
						duplicate = true;
						break;
					}
				if (!duplicate) // Don't allow surface to be added twice (fixes hang)
				{
					psurf->texturechain = r_alpha_surfaces;
					r_alpha_surfaces = psurf;
					psurf->entity = e; // entity pointer to support movement
				}
			}
			.
			.
			.
R_RecursiveWorldNode or other function that adds world surfaces to chains (calling GL_RenderLightmappedPoly directly from R_RecursiveWorldNode is very bad for performance, it causes a pipeline stall when recursing after drawing each face):

Code: Select all

void R_AddWorldSurface (msurface_t *surf)
{
	.
	.
	.
	surf->entity = NULL;	// make sure this is NULL
	.
	.
	.
Addition to start of R_DrawWorld:

Code: Select all

	.
	.
	.
	// auto cycle the world frame for texture animation
	memset (&ent, 0, sizeof(ent));
	
	// Knightmare- added r_worldframe for trans animations
	ent.frame = r_worldframe = (int)(r_newrefdef.time*2); 
	currententity = &ent;
	.
	.
	.
Additions to R_DrawAlphaSurfaces:

Code: Select all

	.
	.
	.
	image_t		*image; // Knightmare added
	.
	.
	.
	for (s = r_alpha_surfaces; s; s = s->texturechain)
	{
		// go back to the world matrix
		qglLoadMatrixf (r_world_matrix);
	
		// disable depth testing for all bmodel surfs (which are not BSP-sorted)
		if (s->entity)
			GL_DepthMask (false);
		else
			GL_DepthMask (true);
	
		// moving trans brushes
		if (s->entity)
			R_RotateForEntity (s->entity, true);
			
		// Knightmare- use animated texture
	//	GL_Bind(s->texinfo->image->texnum);
		image = R_TextureAnimation (s);
		GL_Bind(image->texnum);

		// Draw surface here
		.
		.
		.
	}
	.
	.
	.
	// go back to the world matrix after shifting trans faces
	qglLoadMatrixf (r_world_matrix);
	
	// re-enable depth masking
	qglDepthMask (true);
	.
	.
	.
}
Post Reply