Bezier patch normals and triangle rasterization.

Goragoth

Regular
I'm still working on my bezier patch viewer I posted about earlier and I'm having a couple of problems.

Firstly, you can get an executable of it here (327k).
The source is also there(26.6k). It has VC7 project files but should compile in g++ (have to uncomment USE_VC7 in s3d_defs.h though), however you need the wxWindows toolkit to compile it.

Now to the problems:
1) At some point in the patch the normals all twist around and start pointing down (run the app and crank up the divisions a couple of times and you'll see what I mean, there's a black area). WTF?:devilish: I sort of understand how it might happen but I have no idea how to fix it.

Here's the chunk of code looping around creating vertices:
Code:
for( int yc=0; yc<=quad_dim; yc++ )
	{
		s = 0.0f;
		for( int xc=0; xc<=quad_dim; xc++ )
		{
			// v0:
			CVec3 pre( pow3(s), pow2(s), s );
			CVec3 post( pow3(t), pow2(t), t );
			CVec3 pre2( 3*pow2(s), 2*s, 1.0f, 0.0f );	// 2nd derivative pre
			CVec3 post2( 3*pow2(t), 2*t, 1.0f, 0.0f );	// 2nd derivative post
			CVec3 tmp2, tmp3, tmp4;

			tmp3 = pre * mgmx;
			x[0] = tmp3 ^ &post;

			tmp3 = pre * mgmy;
			y[0] = tmp3 ^ &post;

			tmp3 = pre * mgmz;
			z[0] = tmp3 ^ &post;

			// Calc normals:
			tmp2 = pre * mgmx;
			tmp3[0] = tmp2 ^ &post2;
			tmp2 = pre * mgmy;
			tmp3[1] = tmp2 ^ &post2;
			tmp2 = pre * mgmz;
			tmp3[2] = tmp2 ^ &post2;

			tmp2 = pre2 * mgmx;
			tmp4[0] = tmp2 ^ &post;
			tmp2 = pre2 * mgmy;
			tmp4[1] = tmp2 ^ &post;
			tmp2 = pre2 * mgmz;
			tmp4[2] = tmp2 ^ &post;
			tmp3.Normalize();
			tmp4.Normalize();
			n0 = tmp4 * &tmp3;
			n0.Normalize();

			// Create vertex:
			v0 = Vertex( x[0], y[0], z[0], n0[0], n0[1], n0[2], r, g, b );
			tri_mesh[++curv] = new Vertex( &v0 );

			s += step;
		}
		t += step;
	}
If it doesn't make sense to you grab the source and look at the UpdateMesh() function in the Bezier.cpp file. I should change this function completely to something better but for now I just want this to work because its so close.

2) I'm getting a lot of rendering errors/weird artifacts when gouraud shading. Grab the executable and try it, you will see what I mean. There's no clear pattern to my eyes so its really hard to determine what is wrong. My triangle rasterizer is a bit of a mess anyhow :oops:, perhaps I should try to clean it up a bit first and tweak it, but maybe someone here can spot the problem right away. :)
 
It needs MSVC70.dll?

At a glance I can't guess why the normals are flipping (unless you have a twist in the surface) but I noticed...
Code:
      tmp3.Normalize();
         tmp4.Normalize();
         n0 = tmp4 * &tmp3;
         n0.Normalize();
There's no need to normalise the tangents first - just take the cross product and normalise the result.
 
There's no need to normalise the tangents first
Good point. I was actually thinking of removing it, it was left over from some code and didn't break anything. Changed it now though.

It needs MSVC70.dll?
Apparently so, although I'm not sure why, probably has some stuff in it that VC7 automagically compiles in (like type conversions maybe?).

Hmm, I might check my initial control points and make sure I'm not screwing something up there, I just thought about that, that might cause a twist.

Oh yeah and one last thing: AMD CodeAnalyst rocks! I found out that my backbuffer clearing was slowing things down a lot so I turned a PutPixel() loop into a memset and the program runs much quicker now.
 
Goragoth said:
There's no need to normalise the tangents first
Good point. I was actually thinking of removing it, it was left over from some code and didn't break anything. Changed it now though.

It needs MSVC70.dll?
Apparently so, although I'm not sure why, probably has some stuff in it that VC7 automagically compiles in (like type conversions maybe?).
What I meant was "you need to export it as part of your executable".

Oh yeah and one last thing: AMD CodeAnalyst rocks! I found out that my backbuffer clearing was slowing things down a lot so I turned a PutPixel() loop into a memset and the program runs much quicker now.
:oops: You are drawing pixels with the CPU? Don't you have rendering hardware?
 
What I meant was "you need to export it as part of your executable".
Ok, I've added the dll to the zip file so it should work now. Someone else who I got to try out the program also had a problem with that dll so I guess its not as common as I thought (makes the zip file bigger so I didn't include it earlier).

You are drawing pixels with the CPU? Don't you have rendering hardware?
:D Of course I have hardware but this project is strictly software rendering using the wxWindows library for graphics. Now before you ask why on earth I would use wxWindows for a 3d rasterizer I will provide the answer: because I have to. It is after all a university assignment and I have to play by their rules otherwise I would have at least used DirectDraw. wxWindows is pretty bad actually because I have to use a wxImage object for the backbuffer but you can't draw that to the screen so for every frame I have to create a wxBitmap from the wxImage to display it (and I can't use a wxBitmap as the backbuffer because it has no way of setting pixels, its crazy). :(

Back to the problem at hand: I noticed that as I moved the control points around the black patch (where the normals are inverted) moves around too but never disappears completely. The patch is centered on the origin so some x and z coordinates are negative part of the way, can that influence the normals calculation? This is weird. Maybe I should rewrite the whole damn tesselator from scratch using De Casteljau's algorithm.
 
Fixed it. Turns out my vector constructor had a typo:
Code:
data[0] = x;
data[1] = y;
data[2] = z;
data[3] = x;
No wonder it wasn't working. And I didn't think to look there of all places but working it out by hand and stepping through with the debugger eventually brought me there. Phew!
 
Back
Top