Monday, November 30, 2009

Seams might be handled!

Without seams handled:
With seams handled:
Now with a 3x3 blur, not position dependent:

Dilated seams

Seams are starting to look better:
I've switched back to GL_NEAREST for the texture filtering and implemented my own dilating filter that uses the max value from the texels in a 3x3 area as the fragment color. I'm not sure if this is correct, but I'll move ahead as if it is.

Seams and roundoff error?

I decided to check some of the texture coordinates for the opposite seam directly and see if they mapped to Frank. Some did, some did not. Then moved around the tex coords that mapped to black around by 1 pixel and found that they started mapping to Frank.

This lead to the realization that I was using GL_NEAREST for the texture filtering and not GL_LINEAR. Switching to GL_LINEAR gives the following:This still isn't what I'd expect to see, but at least I know that my seam finding algorithm is probably working correctly.

Continuing seam problems

I'm continuing to have problems with seams.
In this case, Frank is texture baked as a flat red image. I believe that all of the seams should show up as the same color that was used for Frank, ie, the seams should all be red.

In this case, the fragment shader is set up to discover when the resulting color is black and set the seam color to so darker red so that it is obvious what is missing. It is easy to see that a bunch of the information is not transported across to the matching seam.

It looks to me like the tex coords for grabbing the data from the other side of the seam are wrong or are mapping to black spaces.

Here's my code:

// Find seams in the object
void OBJModel::findSeams(void)
// Seams lie along triangle edges. For each triangle, there are
// three possible seams (v0,v1), (v0,v2) and (v1,v2)
// Those lines might be seams if each of the vertices has more than
// one texture coordinate.
for(GLuint tri = 0; tri < _triangles.size(); tri++)
// Make a convenient copy of the vertex and texcoord indices
GLuint v[3];
GLuint t[3];

for(int i = 0; i < 3; i++)
v[i] = _triangles[tri].vertex(i);
t[i] = _triangles[tri].texCoord(i);

Seam sm;

// Find any matching seams for line segment (v0, v1)
sm.v0 = v[0]; sm.v1 = v[1]; sm.t0a = t[0]; sm.t1a = t[1];
findMatchingSeams(sm, tri);

// Find any matching seams for line segment (v0, v2)
sm.v0 = v[0]; sm.v1 = v[2]; sm.t0a = t[0]; sm.t1a = t[2];
findMatchingSeams(sm, tri);

// Find any matching seams for line segment (v1, v2)
sm.v0 = v[1]; sm.v1 = v[2]; sm.t0a = t[1]; sm.t1a = t[2];
findMatchingSeams(sm, tri);

cout << "Seams: " << _seams.size() << endl;
cout << "Duplicate vertices: " << _duplicateVertices.size() << endl;

// Find any matching seams for a line segment
void OBJModel::findMatchingSeams(Seam sm0, GLuint noTri)
// Both of the vertices need to have more than 1 tex coord
// for this to be a seam
if(numTexCoords(sm0.v0) <= 1 || numTexCoords(sm0.v1 <= 1))

// Find triangles with the same vertex indices
for(GLuint tri = 0; tri < _triangles.size(); tri++)
// If this triangle contains these two vertices
if(tri != noTri &&
_triangles[tri].hasVertex(sm0.v0) &&
// Make a copy of the potential seam
Seam sm(sm0);
bool found0 = false;
bool found1 = false;

// Find the tex coords in the matching seam
for(int i = 0; i < 3; i++)
// If vertex index 0 matches vertex index i,
// get the texture coord on the other side of the seam
if(sm.v0 == _triangles[tri].vertex(i))
found0 = true;
sm.t0b = _triangles[tri].texCoord(i);

// If vertex index 1 matches vertex index i,
// get the texture coord on the other side of the seam
if(sm.v1 == _triangles[tri].vertex(i))
found1 = true;
sm.t1b = _triangles[tri].texCoord(i);

// This shouldn't happen and in practice I haven't seen it happen, but
// check anyways
if(!found0 && !found1)
cout << "Found a seam but no matching texcoords" << endl;

// If the tex coords on the other triangle are exactly the same,
// then this isn't a seam. Removing this check results in an image
// that appears exactly the same as the one above
if(!(sm.t0a == sm.t0b && sm.t1a == sm.t1b))
// Add the duplicate vertices

// Add this seam to the list

Saturday, November 28, 2009

Friday, November 27, 2009

Drawing all triangles in texture space

Here's all the triangles drawn in texture space: Notice that the seams aren't necessarily straight. I've been assuming that the triangles would form a nice seam all the way around the model, but it looks like that isn't true. Do I need to match up vertices between different triangles to make the seams?

Duplicate vertices

Drawing the seams w/ duplicate vertices:
What's up with those duplicate vertices all over the place? They should be on the seams.

Thursday, November 26, 2009

Seam triangles - yer doin it wrong?

I might be finding the wrong triangles along the seams:I'd expect to see a line all along the seams where the triangles match up and some scribbliness along the edges where the extra line segments for the rest of the triangles lie. But instead they don't match up perfectly.

Or maybe they are and I'm looking at it wrong? Not sure.

Tuesday, November 24, 2009

Broken seams

Here's a couple of images of broken seams:

The first image is an attempt to transport data from one seam to the matching seam and the second image is generated the same as the first, but the fragment shader just turns the line segments red.

A very large line width was used to illustrate the problem. Here are the same pics but with a smaller (3.0f) line width:

Thursday, November 19, 2009

Saturday, November 14, 2009

Assignment 5.2

The shadowmap rendered in texture space but blurred using the baked position map for the weights:

The background image that can be seen through Frank and rendered in texture space and blurred:

And here those two images are composited on Frank:

I have to say, that image really sucks. Things aren't being composited together correctly and the seams are just awful. Biggest piece of crap image I've produced yet. Seriously. I need to step up my game. The only reason I'm turning in such a POS image is because I've spent waaay too much time on this class and I'm going to burn out. I need to save something for the remaining assignments. Normally I'd just keep cranking until I got something that looked halfway decent.

Here's one clue as to some of the problems I'm having:

This uses the dot product of the normal and light direction to shade the unshadowed parts. Note the difference in the shadow boundary between the part that is shadowed via the shadow map and the die off of the cosine term for the unshadowed part.

Definitely something that I need to fix.

However, I'll be working on seams for the rest of the day and hope that ways to make Frank look better magically pop into my head while working on something else. It's amazing how often tricks like that work.

The blurring was done using a weighted blur that was based on position in space. 9 texels are used in the blur and the distance from the center is calculated. That distance is fed into an exponential, the weights are summed and the center texel is weighted with the remaining weight. This way everything sums to 1 and light energy is conserved.

Download, build and run:

tar jxf assign5.2.tar.bz2
cd assign5.2/assign5.2

Click and drag with the mouse to rotate the camera around Frank.

Saturday, November 7, 2009

Assignment 5.1

Notice how Frank is darker where he is thicker? Notice how more red light makes it through the thicker parts as opposed the the green and blue components? Pretty nice effect. The depth of Frank is calculated at each frame with respect to the light source and the amount of light that makes it through to the other side is calculated using e^(rho * distance). Rho is a 3 component vector with different values for red, green and blue.

Here's an example where the algorithm falls down. The depth is calculated very niavely and only works for convex objects. Frank is a concave object. How the depth calculation works is to determine the farthest depth and the nearest depth, then subtract the two to find the total depth. Since Frank has some holes as some angles, the wrong depth is calculated.

If depth peeling was used, the depths sorted and the holes subtracted out from the total depth, this would work. But it would be really slow.

The next step in this assignment was to make Frank shadow himself. Hard shadows are simple, but in real life flesh lets some of the light through. Instead of doing a binary shadow compare, the distance the light travels through Frank is taken into account and a probability that the light makes it through him is calculated and used as the shadow color. As before, a rho with different values for red, blue and green was used.

Here's the initial probability shadowmap:

Here it is being used to blend with Frank's color:

Download and build:

tar jxf assign5.1.tar.bz2
cd assign5.1/assign5.1

Press q to quit and click and drag the mouse to change your viewpoint.

Sunday, November 1, 2009

Cg fragment discard Leopard vs Snow Leopard

I beat my head against the wall for a while trying to discard fragments in a fragment shader. Each time, everything got discarded. The hypothesis is that the entire fragment bundle was being discarded when a discard was being hit. I suspect that the point sprites I was working with each ended up in an entire fragment bundle.

This caused my particle system to completely disappear.

I kept assuming that I was doing something wrong and kept working away and finally gave up. One day, I tried my code under Linux, threw in a discard statement and everything behaved exactly as I expected.

It wasn't clear if this was a limitation of the video card in my laptop or the driver, so I just plugged along without using discard.

Then I upgraded to Snow Leopard and gave fragment discard another try.

It worked.

This was a driver issue and not a hardware limitation issue.