Sign in to follow this  
blueshogun96

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

Recommended Posts

blueshogun96    2265
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[i][0] = ShaderTexture[i];
		textureData[i][1] = ShaderTexture[i];
		textureData[i][2] = ShaderTexture[i];
	}

	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[i][0]][0]);
		glVertex3fv(&VertexData[TIndices[i][0]][0]);
		glNormal3fv(&VertexData[TIndices[i][1]][0]);
		glVertex3fv(&VertexData[TIndices[i][1]][0]);
		glNormal3fv(&VertexData[TIndices[i][2]][0]);
		glVertex3fv(&VertexData[TIndices[i][2]][0]);*/

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

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

			RotateVector( Matrix, tmpNormal, tmpVector );

			Normalize( tmpVector );

			tmpShade = DotProduct3( tmpVector, fLightAngle );

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

			glTexCoord1f( tmpShade );
			glVertex3fv( &VertexData[TIndices[i][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.

Share this post


Link to post
Share on other sites
aryx    402
The only thing I immediately noticed was
	for( int i = 0; i > 32; i++ )
{
textureData[i][0] = ShaderTexture[i];
textureData[i][1] = ShaderTexture[i];
textureData[i][2] = ShaderTexture[i];
}
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.

Share this post


Link to post
Share on other sites
blueshogun96    2265
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[i][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.

Share this post


Link to post
Share on other sites
aryx    402
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.

Share this post


Link to post
Share on other sites
aryx    402
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!

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this