Debug my rasterizer

Started by
5 comments, last by poefie 9 years, 10 months ago

I don't know whats wrong here, I have two bits of code that do the same thing but only one works and I can't see why.
The first listing draws the blue helicopter. The problem is there are gaps between the triangles. Also some triangles are missing.

Maybe its a fencepost error related to pre-increment in a loop.

Maybe Incorrect accumulation of fractional parts.

Maybe Incorrect cutoff of fractional parts.

Wheres wally?


__forceinline int * floatToInt(int *int_pointer, float f) 
{
	*int_pointer = floor(f);
	return int_pointer;
}


//textureTriangle2D members are all floats
void Rasterizer::textureTriangle(textureTriangle2D & tri)
{
	real temp; // real is a float
	int slopeLeft;
	int slopeRight;

	//sort top to bottom
	//y is 0 at top of screen
	if (tri.y1 > tri.y3)
	{
		SWAP(tri.y1, tri.y3, temp);
		SWAP(tri.x1, tri.x3, temp);
	}

	if (tri.y1 > tri.y2)
	{
		SWAP(tri.y1, tri.y2, temp);
		SWAP(tri.x1, tri.x2, temp);
	}

	if (tri.y2 > tri.y3)
	{
		SWAP(tri.y2, tri.y3, temp);
		SWAP(tri.x2, tri.x3, temp);
	}

	//height of top and bottom half of triangle
	real topHeight = tri.y2 - tri.y1;
	real bottomHeight = tri.y3 - tri.y2;

	floatToInt(&slopeRight, ((tri.x2 - tri.x1) * 65536) / topHeight);
	floatToInt(&slopeLeft, ((tri.x3 - tri.x1) * 65536) / (topHeight + bottomHeight));

	int x1, x2, y1;
	floatToInt(&x1, tri.x1 * 65536);
	x2 = x1;
	floatToInt(&y1, tri.y1);

	int currentLocation;
	currentLocation = (pitch * y1);

	//flat bottom
	int h = floor(topHeight);
	if (h > 0)
	{
		if (tri.x2 > tri.x1)
			flatBottomTriangle(x1, slopeLeft, x2, slopeRight, h, currentLocation);
		else
			flatBottomTriangle(x2, slopeRight, x1, slopeLeft, h, currentLocation);
	}
	
	int offset;
	floatToInt(&offset, slopeLeft * floor(topHeight));
	x1 = x1 + offset;
	floatToInt(&x2, tri.x2 * 65536);

	currentLocation += pitch *floor(topHeight);
	floatToInt(&slopeRight, ((tri.x3 - tri.x2) * 65536) / (bottomHeight));

	int h = floor(bottomHeight);
	if (h > 0)
	{
		if (tri.x2 > tri.x1)
			flatBottomTriangle(x1, slopeLeft, x2, slopeRight, h, currentLocation);
		else
			flatBottomTriangle(x2, slopeRight, x1, slopeLeft, h, currentLocation);
	}
}

__forceinline void flatBottomTriangle(int x1, int slopeLeft, int x2, int slopeRight, real height, int currentLocation)
{
	do
	{	
		x1 += slopeLeft;
		x2 += slopeRight;
		
		int index = currentLocation + (x1 >> 16);
		while ( index ++ < currentLocation+(x2 >> 16) )
		{
			//show overlapping pixels in red
			if (screenBuffer[index ] == 0)
				screenBuffer[index ] = 255;
			else
				screenBuffer[index ] = 255 << 16;
		}

		currentLocation += pitch;
	}
	while( --height > 0  );
}

For what its worth I also have the following code which does the same thing and works. I can't see the difference. It draws they grey helicopter.


__forceinline int * floatToInt(int *int_pointer, float f) 
{
	*int_pointer = floor(f);
	/*__asm  fld f;
	__asm  mov edx,int_pointer;
	__asm  FRNDINT;
	__asm  fistp dword ptr [edx];*/
	return int_pointer;
}
	
//all textureTriangle2D members are floats
void Rasterizer::flatTriangle( flatTriangle2D & tri )
{
	real temp;
	int clip;
	bool topDone = false;

	if ( tri.y1 > tri.y3 )
	{
		SWAP( tri.x1, tri.x3, temp );
		SWAP( tri.y1, tri.y3, temp );
	}

	if ( tri.y1 > tri.y2 )
	{
		SWAP( tri.y1, tri.y2, temp );
		SWAP( tri.x1, tri.x2, temp );
	}

	if ( tri.y2 > tri.y3 )
	{
		SWAP( tri.x2, tri.x3, temp );
		SWAP( tri.y2, tri.y3, temp );
	}

	real x2x1 = tri.x2 - tri.x1;
	real x3x1 = tri.x3 - tri.x1;
	real x3x2 = tri.x3 - tri.x2;

	real y3y1 = tri.y3 - tri.y1;
	real y3y2 = tri.y3 - tri.y2;
	real y2y1 = tri.y2 - tri.y1;

	int x1;
	int x2;
	int y1;
	int y2;
	int y3;
	int tmp1 = 0;
	int tmp2 = 0;
	
	floatToInt( &y1,  tri.y1  );
	floatToInt( &y2,  tri.y2  );
	floatToInt( &y3,  tri.y3  );

	int shortSlope;
	int longSlope;
	
	floatToInt( &longSlope, ( x3x1 * 65536 ) / y3y1 );

	//flat bottom
	if ( y1 != y2 ) 
	{
		topDone = true;

		floatToInt( &x1, tri.x1 * 65536 );
		floatToInt( &shortSlope, ( x2x1 * 65536 ) / y2y1 );
		x2 = x1;

		for (; y1 < y2; y1++)
		{
			if ( x2 > x1 )
			{
				tmp1 = x1 >> 16;
				tmp2 = x2 >> 16;

				if ( tmp1 < clipRect.left )
					tmp1 = clipRect.left;
			
				if ( tmp2 > clipRect.right )
					tmp2 = clipRect.right;

				if ( tmp1 < clipRect.right && tmp2 > clipRect.left)
					hLine( tmp1, tmp2, y1, tri.colour );
			}
			else // from x2 to x1
			{
				tmp1 = x2 >> 16;
				tmp2 = x1 >> 16;

				if ( tmp1 < clipRect.left)
					tmp1 = clipRect.left;

				if ( tmp2 > clipRect.right )
					tmp2 = clipRect.right;

				if ( ( tmp1 < clipRect.right ) && ( tmp2 > clipRect.left ) )
					hLine( tmp1, tmp2, y1, tri.colour );
			}

			x1 += shortSlope;
			x2 += longSlope;
		}
	}

	//flat top
	if ( y2 != y3 )
	{
		floatToInt( &x1, tri.x2 * 65536 );

		if ( ! topDone )
		{
			floatToInt( &x2, tri.x1 * 65536 );
		}

		floatToInt( &shortSlope, ( x3x2 * 65536 ) / y3y2 );

		for (; y2 < y3; y2++)
		{
			if ( x2 >= x1 )
			{
				tmp1 = x1 >> 16;
				tmp2 = x2 >> 16;

				if ( tmp1 < clipRect.left )
					tmp1 = clipRect.left;
			
				if ( tmp2 > clipRect.right )
					tmp2 = clipRect.right;

				if ( tmp1 < clipRect.right && tmp2 > clipRect.left)
					hLine( tmp1, tmp2, y2, tri.colour );
			}
			else // x2 starts x1 ends
			{
				tmp1 = x2 >> 16;
				tmp2 = x1 >> 16;

				if ( tmp1 < clipRect.left)
					tmp1 = clipRect.left;

				if ( tmp2 > clipRect.right )
					tmp2 = clipRect.right;

				if ( ( tmp1 < clipRect.right ) && ( tmp2 > clipRect.left ) )
					hLine( tmp1, tmp2, y2, tri.colour );
			}

			x1 += shortSlope;
			x2 += longSlope;
		}
	}	
}


inline void Rasterizer::hLine(int x, int x1, int y, COLOUR_DEPTH colour)
{				
	y *= pitch;
	while (x < x1)
	{
		screenBuffer[ y + x++ ] = colour;
	}
}
Advertisement

I dont know, maybe I will lok a bit later, but incidentally can you say me maybe why you use floatToInt? also could you maybe say how is you perspective cast transformation look like? are you using 1/z or some matrix (i was using 1/z and some say that its wrong) Also have you maybe some code for quick rasterisation of the sphere or other shapes?

floatToInt is for faster integer conversion than casting. I replaced it with floor for your readability.

I do 1/z too:

zInv1 = 1 / it.vert1.z;

it.vert1.x = ( viewDistance * it.vert1.x ) * zInv1;
it.vert1.y = ( viewDistance * -it.vert1.y ) * (aspectRatio * zInv1);

I don't have fast code sorry.

floatToInt is for faster integer conversion than casting. I replaced it with floor for your readability.

I do 1/z too:

zInv1 = 1 / it.vert1.z;

it.vert1.x = ( viewDistance * it.vert1.x ) * zInv1;
it.vert1.y = ( viewDistance * -it.vert1.y ) * (aspectRatio * zInv1);

I don't have fast code sorry.

I was doing very the same thing as you -

1) also used floatToInt

2) also had triangle rasterization very the same as you (tested both fixed points and floats - though your is looking a bit nicer)

3) also used 1/z

It was year ago and later i leave it untouched, but can comment

(share some knowledge)

1) floatToInt was needed on bcc32 but on present mingw compiler is no need for that (afaik it use oe asm opcode started from pentium3 probably)

2) it worked okay, dont remember exactly but fixedpoint was only very slightly faster (25% or so) - though if rasterized veru small checked board patterns i got wandering patterns on this (moiro patterns?)

2b) I also checked this second approach (halfspace? or what it is called, this nick capens way but also it was as far as i remember just slightly faster (30%?) and only for soma cases not all, though i was doing it on old machine presently I should probably test it all again - (I also got no fast code though anyway i was happy with results)

3) still i dont remember exactly but this kind of projection is probably incorrect, but forgot the details now - as i leave this code in the state like yours by now

[ps. Im not to much advanced, will try to look on yr code why it iznt working but a bit later, Im a bit tired presently]

Thanks for the tips fir, I will look into it when I get there again.

I finally fixed it!

The missing triangles were fixed by using slope size instead of vertex position to determine the direction of a line scan. if(slope1>slope2) instead of if(x1>x2) .

The gaps were fixed by using height= floor(y2)-floor(y1) instead of height=floor(y2-y1). Because |a-b| <= |a|-|b| so |10-5.9|=4 but |10|-|5.9|=5.

Thanks for the tips fir, I will look into it when I get there again.

I finally fixed it!

The missing triangles were fixed by using slope size instead of vertex position to determine the direction of a line scan. if(slope1>slope2) instead of if(x1>x2) .

The gaps were fixed by using height= floor(y2)-floor(y1) instead of height=floor(y2-y1). Still trying to wrap my head around this one but it works.

great, we are doing curiously the same thing - if so we could discus some topics maybe, though i just skipped some bit harder things i should resolwe, for example i would be courious how someone did correct near plane clipping for triangle (i just skipped that (throwing away even partially rear traingles)) also it would be good to optymize it from this strightforward way you and I have gere into something faster (but i dont know how), also some object/mesh file loader awaits me too :C

Hmm, if a merger of our enterprises could be a strategic fit we might fast track a proactive result driven game plan with win-win synergy and out-of-the-box thinking. Hardball!

I'd rather profile than optimize, and to do that I need a fully working engine with all the bells and whistles first.

This topic is closed to new replies.

Advertisement