Cel-Shading: No matter what I do, it never works.

Started by
4 comments, last by aryx 14 years, 2 months ago
I've been working on this Cel-Shading code for a long time and I've never for the life of me been able to get it to work! My code is based off of the NeHe tutorial (#37) and as far as I can tell, I've always followed it to the exact detail! So far, my geometry just comes out black always. Been at this for ages and still can't figure it out. What's going on?? Here's code below: Global variables & defines. The vertices make a Icosahedron and for each vertex, the normal is the same as the vertex value itself.

//-----------------------------------------------------------------------------
// Global variables
//-----------------------------------------------------------------------------
#define X	0.525731112119133606f
#define Z	0.850650808352039932f

// Vertices
static GLfloat VertexData[12][3] = 
{
	{-X, 0.0f, Z }, { X, 0.0f, Z }, {-X, 0.0f,-Z }, { X, 0.0f,-Z },
	{ 0.0f, Z, X }, { 0.0f, Z,-X }, { 0.0f,-Z, X }, { 0.0f,-Z,-X }, 
	{ Z, X, 0.0f }, {-Z, X, 0.0f }, { Z,-X, 0.0f }, {-Z,-X, 0.0f }, 
};

// Indices
static GLint TIndices[20][3] = 
{
	{0,4,1},  {0,9,4},  {9,5,4},  {4,5,8},  {4,8,1},
	{8,10,1}, {8,3,10}, {5,3,8},  {5,2,3},  {2,7,3},
	{7,10,3}, {7,6,10}, {7,11,6}, {11,0,6}, {0,1,6},
	{6,1,10}, {9,0,11}, {9,11,2}, {9,2,5},  {7,2,11}
};

// Light angle
GLfloat fLightAngle[3] = { 0.0f, 0.0f, 1.0f };

// Floating point texture values
GLfloat ShaderTexture[] = 
{
	0.2, 0.2, 0.2, 0.2, 0.5, 0.5, 0.5, 0.5, 
	0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 1.0, 1.0, 
	1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 
	1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0
};

GLuint	uShaderTexture = 0;		// Handle to the shader texture

These are the math functions I've been using. They are the same as the NeHe tutorial as well.

//-----------------------------------------------------------------------------
// Basic math functions
//-----------------------------------------------------------------------------

inline float DotProduct3( float v1[3], float v2[3] )
{
	return v1[0]*v2[0] + v1[1]*v2[1] + v1[2]*v2[2];
}

inline float Magnitude( float v[3] )
{
	return sqrtf(v[0]*v[0] + v[1]*v[1] + v[2]*v[2]);
}

void Normalize( float v[3] )
{
	float m = Magnitude(v);

	if( m != 0.0f )
	{
		v[0] /= m;
		v[1] /= m;
		v[2] /= m;
	}
}

void RotateVector( float m[16], float v[3], float d[3] )
{
	d[0] = (m[0]*v[0])+(m[4]*v[1])+(m[8] *v[2]);
	d[1] = (m[1]*v[0])+(m[5]*v[1])+(m[8] *v[2]);
	d[2] = (m[2]*v[0])+(m[6]*v[1])+(m[10]*v[2]);
}

This is where I initialized my default render states and the 1D cel-shading texture:

	//
	// Set default render states
	//

	// Enable depth testing 
	glEnable( GL_DEPTH_TEST );
	glDepthFunc( GL_LESS );
	glClearDepth( 1.0f );

	// Disable lighting
	glDisable( GL_LIGHTING );
//	glEnable( GL_LIGHTING );

	// Disable texture mapping (for now)
	glDisable( GL_TEXTURE_2D );
	// Enable 1D texture mapping
	glEnable( GL_TEXTURE_1D );

	// Disable blending
	glDisable( GL_BLEND );

	// Disable dithering
	glDisable( GL_DITHER );

	// Enable perspective correction and polygon smoothing
	glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST );
	glHint( GL_POLYGON_SMOOTH_HINT, GL_NICEST );

	// Change the default clear colour to blue
	glClearColor( 0.0f, 0.0f, 0.5f, 1.0f );

	// Create the shader texture
	GLfloat textureData[32][3];

	glGenTextures( 1, &uShaderTexture );

	for( int i = 0; i > 32; i++ )
	{
		textureData[0] = ShaderTexture;
		textureData[1] = ShaderTexture;
		textureData[2] = ShaderTexture;
	}

	glBindTexture( GL_TEXTURE_1D, uShaderTexture );

	glTexParameteri( GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
	glTexParameteri( GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );

	glTexImage1D( GL_TEXTURE_1D, 0, GL_RGB, 32, 0, GL_RGB, GL_FLOAT, textureData );

	Normalize( fLightAngle );

Okay, now for the rendering part.

// Move the camera back and rotate the object
	glTranslatef( 0.0f, 0.0f,-3.0f );
	glRotatef( rotY, 0.0f, 1.0f, 0.0f );

	// Get the current matrix (after transformation)
	glGetFloatv( GL_MODELVIEW_MATRIX, Matrix );

	// Render in wireframe mode.
//	glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );

	//
	// Cel-Shading code
	//

	// Enable 1D textures and bind the shader texture
	glEnable( GL_TEXTURE_1D );
	glBindTexture( GL_TEXTURE_1D, uShaderTexture );

	// Default mesh colour
	glColor3f( 1.0f, 1.0f, 1.0f );

	// Render Icosahedron
	glBegin(GL_TRIANGLES);

	for( int i = 0; i < 20; i++ )
	{
                // This works fine for normal rendering (lighting included).
		/*glNormal3fv(&VertexData[TIndices[0]][0]);
		glVertex3fv(&VertexData[TIndices[0]][0]);
		glNormal3fv(&VertexData[TIndices[1]][0]);
		glVertex3fv(&VertexData[TIndices[1]][0]);
		glNormal3fv(&VertexData[TIndices[2]][0]);
		glVertex3fv(&VertexData[TIndices[2]][0]);*/

		for( int j = 0; j < 3; j++ )
		{
			float tmpNormal[3], tmpVector[3], tmpShade;

			tmpNormal[0] = VertexData[TIndices[j]][0];
			tmpNormal[1] = VertexData[TIndices[j]][1];
			tmpNormal[2] = VertexData[TIndices[j]][2];

			RotateVector( Matrix, tmpNormal, tmpVector );

			Normalize( tmpVector );

			tmpShade = DotProduct3( tmpVector, fLightAngle );

			if( tmpShade < 0.0f )
				tmpShade = 0.0f;

			glTexCoord1f( tmpShade );
			glVertex3fv( &VertexData[TIndices[j]][0] );
		}
	}

	glEnd();

So hopefully one of the more experienced members of gamedev.net can give me a hand. They make it look easy, but I guess it isn't. This sucks. Any ideas? Thanks.
Advertisement
The only thing I immediately noticed was
	for( int i = 0; i > 32; i++ )	{		textureData[0] = ShaderTexture;		textureData[1] = ShaderTexture;		textureData[2] = ShaderTexture;	}
Maybe you might want a less than instead of greater than. Don't know if that's the root of the issue but I thought I'd point it out!

[EDIT]
Look like you have some indexing issues in RotateVector also.
Okay, I fixed the shading part. Switching from < to > did the trick, Thanks! But now the outline doesn't appear to work properly. It just renders as a wireframe copy of the mesh. I think it has to do with blending, but quite frankly, I don't understand what it's blending! Throughout the whole tutorial, I didn't see the alpha bit set not one time. This is what I have for the outline:

// Enable blending for the outline	glEnable( GL_BLEND );	glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );	// Render back facing polygons as wireframe	glPolygonMode( GL_BACK, GL_LINE );	glLineWidth( 3.0f );	// Cull front facing polygons	glCullFace( GL_FRONT );	// Change the depth test mode to GL_LEQUAL	glDepthFunc( GL_LEQUAL );	glColor3f( 0.0f, 0.0f, 0.0f );	// Render the object again for the outlines	glBegin( GL_TRIANGLES );	for( i = 0; i < 20; i++ )	{		for( int j = 0; j < 3; j++ )		{			glVertex3fv( &VertexData[TIndices[j]][0] );		}	}	glEnd();	// Revert back to previous render states	glDepthFunc( GL_LESS );	glCullFace( GL_BACK );	glPolygonMode( GL_BACK, GL_FILL );	glDisable( GL_BLEND );


Either way, I'm still quite satisfied with the fact that the cel-shading part works. Thanks.
I don't think I see you enabling culling anywhere [i.e., glEnable(GL_CULL_FACE)]. Nevertheless, I still find it funny that you'd see a wireframe model since the back-facing polygons should [mostly] fail the depth test, and the front facing polygons should probably render as filled polygons. I guess blending would cause that problem, so try the glEnable for culling and see what happens.
Tried it. Now it appears as if the light is coming from the other direction. It didn't solve the outlining problem though.
I tried integrating your code into the nehe tutorial's code, and had difficulties. From what I can tell though, I think your vertex indicies may not be correct, so try double checking those. Also verify that your winding order is correct. If it is correct all the way around, you might have to change the front facing polygons to be CW [i.e., glFrontFace(GL_CW)].

Also, make sure you're resetting the modelview matrix to the identity before applying glTranslate/glRotate, otherwise your operations will just stack on top of each other every time you draw.

That's about all I can suggest for now. Hope this helps!

This topic is closed to new replies.

Advertisement