[C++/OpenGL] Toon (Cel) Shader

Post those lines of code you feel like sharing or find what you require for your project here; or simply use them as tutorials.
Post Reply
sio2
Competition winner
Posts: 1003
Joined: Thu Sep 21, 2006 5:33 pm
Location: UK

[C++/OpenGL] Toon (Cel) Shader

Post by sio2 »

Here's a Toon/Cel GLSL shader for Irrlicht/OpenGL. High-Level GLSL shaders 1.1 or above required.

This snippet is now available as a demo from my website. Compiled exe, source and VS2005 project file included in demo.

Note: Shader based on lighthouse3d.com

Screenshot:
Image

Code: Select all

// --------------------------------------------------------------------------
// Irrlicht Toon (Cel) Shader Demo
// sio2 'at' users.sourceforge.net
// --------------------------------------------------------------------------

#include <irrlicht.h>

// --------------------------------------------------------------------------

using namespace irr;
using namespace core;
using namespace scene;
using namespace video;
using namespace io;
using namespace gui;

// --------------------------------------------------------------------------

#pragma comment(lib, "Irrlicht.lib")

// --------------------------------------------------------------------------

// OpenGL Vertex Program 1.1
const stringc vertToonShader =
"varying vec3 normal;"
"void main()"
"{"
"	normal = gl_NormalMatrix * gl_Normal;"
"	gl_Position = ftransform();"
"}";

// --------------------------------------------------------------------------

// OpenGL Fragment Program 1.1
const stringc fragToonShader =
"varying vec3 normal;"
"void main()"
"{"
"	float intensity;"
"	vec4 color;"
"	vec3 n = normalize(normal);"
""
"	intensity = dot(vec3(gl_LightSource[0].position),n);"
""
"	if (intensity > 0.95)"
"		color = vec4(1.0,0.5,0.5,1.0);"
"	else if (intensity > 0.5)"
"		color = vec4(0.6,0.3,0.3,1.0);"
"	else if (intensity > 0.25)"
"		color = vec4(0.4,0.2,0.2,1.0);"
"	else"
"		color = vec4(0.2,0.1,0.1,1.0);"
""
"	gl_FragColor = color;"
"}";

// --------------------------------------------------------------------------

int main()
{
	// Create device
	video::E_DRIVER_TYPE driverType = video::EDT_OPENGL;
	IrrlichtDevice *device = createDevice(driverType, dimension2di(800, 600), 32, false, false, false, 0);
	if (!device) {
		printf("Error creating Irrlicht device\n");
		return 0;
	}

	// Obtain device internals
	IVideoDriver* driver = device->getVideoDriver();
	ISceneManager* smgr = device->getSceneManager();

	// Set a window caption
	device->setWindowCaption(L"ToonShader - Irrlicht Engine Demo");

	// Create GLSL shaders
	video::IGPUProgrammingServices* gpu = driver->getGPUProgrammingServices();
	s32 mtlToonShader = video::EMT_SOLID; // Fallback material type
	bool bCanDoGLSL_1_1 = false;
	if (gpu && (driverType == video::EDT_OPENGL)) {
		bCanDoGLSL_1_1 = true; // provisionally accept
		if (!driver->queryFeature(video::EVDF_ARB_FRAGMENT_PROGRAM_1)) {
			printf("queryFeature(video::EVDF_ARB_FRAGMENT_PROGRAM_1) failed\n");
			bCanDoGLSL_1_1 = false;
		}
		if (!driver->queryFeature(video::EVDF_ARB_VERTEX_PROGRAM_1)) {
			printf("queryFeature(video::EVDF_ARB_VERTEX_PROGRAM_1) failed\n");
			bCanDoGLSL_1_1 = false;
		}
	}
	if (bCanDoGLSL_1_1) {
		// Shader uses built-in OpenGL GLSL uniforms, hence needs no explicit constants.
		// Therefore a callback function is not needed and is NULL.
		mtlToonShader = gpu->addHighLevelShaderMaterial(
					vertToonShader.c_str(), "main", video::EVST_VS_1_1,
					fragToonShader.c_str(), "main", video::EPST_PS_1_1,
					NULL, video::EMT_SOLID);
	} else {
		// This demo is for OpenGL!
		printf("This demo requires OpenGL with GLSL High-Level shaders\n");
		mtlToonShader = video::EMT_SOLID;
	}

	// Add an animated mesh
	IAnimatedMesh* mesh = smgr->getMesh("../../media/sydney.md2");
	IAnimatedMeshSceneNode* node = smgr->addAnimatedMeshSceneNode( mesh );
	if (node)
	{
		node->setMaterialFlag(EMF_LIGHTING, false);
		node->setMD2Animation ( scene::EMAT_STAND );
		node->setMaterialTexture( 0, driver->getTexture("../../media/sydney.bmp") );
		node->setMaterialType((video::E_MATERIAL_TYPE)mtlToonShader); // Override material type
	}

	// Add a viewing camera
	smgr->addCameraSceneNode(0, vector3df(0,30,-40), vector3df(0,5,0));

	// Main rendering loop
	while(device->run())
	{
		driver->beginScene(true, true, SColor(255,100,101,140));
		smgr->drawAll();
		driver->endScene();
	}

	device->drop();

	// Done
	return 0;
}

// --------------------------------------------------------------------------
Last edited by sio2 on Sat Jan 20, 2007 10:17 am, edited 1 time in total.
lug
Posts: 79
Joined: Tue May 02, 2006 5:15 am
Contact:

Post by lug »

:shock: lug rubs eyes :shock:
JPulham
Posts: 320
Joined: Sat Nov 19, 2005 12:06 pm

Post by JPulham »

nice! :D
pushpork
BlindSide
Admin
Posts: 2821
Joined: Thu Dec 08, 2005 9:09 am
Location: NZ!

Post by BlindSide »

Nice, you could have saved me trouble if you did this earlier :lol:

(HLSL version available in my topic)

PS: If you want more features like specular etc, you can try converting ogres' CG shader to GLSL but remember to disable filtering on all texture ramps 8)

I should have put a better example like your on mine :oops:

Also, GLSL is weird, whats with Lightsource[0] and stuff. I havent had a chance to study GLSL because my card only supports FRAGMENT_TEXT which is not available to irrlicht (It requires assembly shaders)

Oh yes before I forget thx for making one for GLSL! Good work :D
wowdevver24
Posts: 26
Joined: Mon Jan 04, 2010 8:02 pm

Post by wowdevver24 »

I would rename this to a clay renderer, it looks nothing like a cartoon and from what I can see has no stroke width setting
Remember all information is contextual and if I do not understand the context I cannot gras the information
hybrid
Admin
Posts: 14143
Joined: Wed Apr 19, 2006 9:20 pm
Location: Oldenburg(Oldb), Germany
Contact:

Post by hybrid »

AFAIK there's no official specification which requires a stroke width?! cell shading just means that the shading is made in only a few larger regions. Of course, you can provide an enhanced version here.
Post Reply