Advertisement

I'm in dire need of someone who knows this stuff

Started by January 21, 2006 04:18 PM
3 comments, last by TerraX 18 years, 7 months ago
I wrote a particle system once for a 2d game that worked great and I decided to adapt it to 3d and I plan on adding things like wind resistance and all kinds of stuff but anyway. I am currently implementing 3 different rendering methods... cpu billboarding, arb point sprites (GL_EXT), and a cg vertex shader billboarding. both the cpu billboarding and cg vertex shader billboarding don't blend the particles correctly. For instance when you look down with the camera at the particles, it doesn't blend right, and in some other instances. And the arb point sprites don't draw at all. If you can spot anything in this code please let me know. I'd like to move on for now from particles but it's been bugging me. Here's the drawing code

void cParticleSystem::Draw(void){
	cParticle *index = head;

	glEnable(GL_TEXTURE_2D);
	glEnable(GL_BLEND);
	glDisable(GL_LIGHTING);
	
	glBindTexture(GL_TEXTURE_2D, texture[0]);
	glBlendFunc( GL_SRC_ALPHA, GL_ONE );

	if (renderMethod == CPU_BILLBOARDS){
		double mat[16];
		glGetDoublev( GL_MODELVIEW_MATRIX, mat );
		cVector3 right(mat[0], mat[4], mat[8]);
		cVector3 up(mat[1], mat[5], mat[9]);
		cVector3 point0, point1, point2, point3;

		while (index){
			cVector3 point0 = index->position + (((-right) - up) * index->size );
			cVector3 point1 = index->position + ((right - up) * index->size );
			cVector3 point2 = index->position + ((right + up) * index->size );
			cVector3 point3 = index->position + (((-right) + up) * index->size );

			cVector3 color;
			if (index->life > 1.0){
				double percent = ((index->life - 1.0) / (index->startLife - 1.0));
				double oneMinusPercent = 1.0 - percent;
				color = (startColor * percent) + (endColor * oneMinusPercent);
			}else{
				color = endColor;
			}

			glColor4d(color.x, color.y, color.z, index->life);

			glBegin(GL_QUADS);
			glTexCoord2d(0, 0); glVertex3f(point0.x, point0.y, point0.z);
			glTexCoord2d(1, 0); glVertex3f(point1.x, point1.y, point1.z);
			glTexCoord2d(1, 1); glVertex3f(point2.x, point2.y, point2.z);
			glTexCoord2d(0, 1); glVertex3f(point3.x, point3.y, point3.z);
			glEnd();

			index = index->next;
		}
	}else if( renderMethod == ARB_POINT_SPRITES ){
		float quadratic[] =  { 1.0f, 0.0f, 0.01f };
		glPointParameterfvARB( GL_POINT_DISTANCE_ATTENUATION_ARB, quadratic );

		glPointParameterfARB( GL_POINT_FADE_THRESHOLD_SIZE_ARB, 60.0f );

		glPointParameterfARB( GL_POINT_SIZE_MIN_ARB, 1.0f );
		glPointParameterfARB( GL_POINT_SIZE_MAX_ARB, index->size );

		glTexEnvf( GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE );

		glEnable( GL_POINT_SPRITE_ARB );
		
		while( index ){
			glPointSize( index->size );
	
			cVector3 color;
			if (index->life > 1.0){
				double percent = ((index->life - 1.0) / (index->startLife - 1.0));
				double oneMinusPercent = 1.0 - percent;
				color = (startColor * percent) + (endColor * oneMinusPercent);
			}else{
				color = endColor;
			}
	
			glColor4d(color.x, color.y, color.z, index->life);
			glBegin( GL_POINTS );
				glVertex3d( index->position.x, index->position.y, index->position.z);
				index = index->next;
			glEnd();
		}

		glDisable( GL_POINT_SPRITE_ARB );
	}else if( renderMethod == CG_VERTEX_SHADER ){
		cParticle  *index = head;

        // Compute billboard vertices on the GPU...
        // Track the combined model-view-projection matrix
		cgGLSetStateMatrixParameter( m_CGparam_modelViewProj,
									 CG_GL_MODELVIEW_PROJECTION_MATRIX,
									 CG_GL_MATRIX_IDENTITY );

        // Load the billboard size into a constant register
        //float fSize[] = { 1.0f, 0.0f, 0.0f, 0.0f };
        //cgGLSetParameter4fv( m_CGparam_size, fSize );

        // Create a pre-rotated quad for use by the shader...

		float mat[16];
		glGetFloatv( GL_MODELVIEW_MATRIX, mat );

		cVector3f vRight( mat[0], mat[4], mat[8] );
		cVector3f vUp( mat[1], mat[5], mat[9] );
		cVector3f vCenter( 0.0f, 0.0f, 0.0f );

		cVector3f vPoint0 = vCenter + (-vRight - vUp);
		cVector3f vPoint1 = vCenter + ( vRight - vUp);
		cVector3f vPoint2 = vCenter + ( vRight + vUp);
		cVector3f vPoint3 = vCenter + (-vRight + vUp);

		float preRotatedQuad[16] = {
			vPoint0.x, vPoint0.y, vPoint0.z, 0.0f,
			vPoint1.x, vPoint1.y, vPoint1.z, 0.0f,
			vPoint2.x, vPoint2.y, vPoint2.z, 0.0f,
			vPoint3.x, vPoint3.y, vPoint3.z, 0.0f
		};

		cgGLSetParameterArray4f( m_CGparam_preRotatedQuad, 0, 4, preRotatedQuad );

        // Bind the shader and render the particles...
		cgGLBindProgram( m_CGprogram );
		cgGLEnableProfile( m_CGprofile );

		glBindTexture( GL_TEXTURE_2D, texture[0] );

		float fAdjustedSize = index->size;

		glBegin( GL_QUADS );{
			while( index ){
				cVector3 color;
				if (index->life > 1.0){
					double percent = ((index->life - 1.0) / (index->startLife - 1.0));
					double oneMinusPercent = 1.0 - percent;
					color = (startColor * percent) + (endColor * oneMinusPercent);
				}else{
					color = endColor;
				}
	
				glColor4d(color.x, color.y, color.z, index->life);

				vCenter.x = index->position.x;
				vCenter.y = index->position.y;
				vCenter.z = index->position.z;
                
				glTexCoord4f( 0.0f, 0.0f, 0.0f, fAdjustedSize );
				glVertex3f( vCenter.x, vCenter.y, vCenter.z );

				glTexCoord4f( 1.0f, 0.0f, 1.0f, fAdjustedSize );
				glVertex3f( vCenter.x, vCenter.y, vCenter.z );

				glTexCoord4f( 1.0f, 1.0f, 2.0f, fAdjustedSize );
				glVertex3f( vCenter.x, vCenter.y, vCenter.z );

				glTexCoord4f( 0.0f, 1.0f, 3.0f, fAdjustedSize );
				glVertex3f( vCenter.x, vCenter.y, vCenter.z );

				index = index->next;
			}
		}
		glEnd();

		cgGLDisableProfile( m_CGprofile );
	}
}

Douglas Eugene Reisinger II
Projects/Profile Site
Just a stab in the dark here as I'm knackered from fighting coding MD3 stuff but usually your blendfunc is GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA for normal blending, not GL_SRC_ALPHA, GL_ONE as you currently have it.

Like I say it's just the first thing I noticed, may not be any help to you but I hope it is.

Best of luck.
--
Cheers,
Darren Clark
Advertisement
Note that, for some blend modes, you need to actually sort the particles far-to-near before generating the geometry, each frame.

For particles with additive blending mode (ONE, ONE), draw order doesn't matter.
enum Bool { True, False, FileNotFound };
try disabling depthwriting with glDepthMask(GL_FALSE);
this will inshure that particles won't block each other.

You will still need to sort them though.
I find that if I disable depth writing and use glDepthFunc(GL_SRC_ALPHA, GL_ONE);

Everything is fine... however, it's when I set the blending to take into consideration what's behind it with glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA), then I need to sort everything by depth and render from back to front.

I recommend doing what someone else here mentioned and simply disable depth writing while rendering the particles, it's fast, is OK to look at and takes into consideration, previously rendered geometry (It also prevents each particle being rendered, no matter how far away it is, from culling the pixels of the next to be rendered particle if it's Z depth is greater than any previously rendered) I pretty much always render the particle systems last.

However, saying all that, after looking at your supplied code, I doubt this will help, as I see no state changes... so perhaps it's not the problem... I dunno... I blame beer.

This topic is closed to new replies.

Advertisement