WorldBuilding/Visual Style/Cel Shading/Code
From TDN
Contents |
Engine Code Changes
In TGE, there will be no perfect solution for Cel-Shading. True Cel-Shading cannot be achieved without big rendering changes, but the code below is provided to create an outline for the terrain, shapes and interiors. There are some big differences between the DirectX and OpenGL (Using this code). It is recommended that you look into Stencil Shadows, help define this visual style. A word of caution, this code and cel-shading in general is a serious fps hit.
The code presented below is largly from this forum thread:
Topic: cartoon outlining (cartoon rendering part1)
Insert/Replace these lines of code for each appropriate area.
Shapes
in ts/tsMesh.cc
in TSMesh::render after:
S32 drawType = getDrawType(draw.matIndex>>30); glDrawElements(drawType,draw.numElements,GL_UNSIGNED_SHORT,&indices[draw.start]); }
add
/*cell shading*/
bool doOutline=Con::getBoolVariable("$Pref::renderOutline",true);
if (doOutline) {
bool oldlighting=glIsEnabled(GL_LIGHTING);
glDisable(GL_LIGHTING);
F32 oldLineWidth;
glGetFloatv(GL_LINE_WIDTH,&oldLineWidth);
F32 lineWidth=Con::getFloatVariable("$Pref::OutlineWidth",2);
glLineWidth(lineWidth);
glCullFace(GL_FRONT);
glPolygonMode (GL_BACK, GL_LINE);
glDepthFunc(GL_LEQUAL);
bool old2dtex=glIsEnabled(GL_TEXTURE_2D);
glDisable(GL_TEXTURE_2D);
F32 oldcolor[4];
glGetFloatv(GL_CURRENT_COLOR,oldcolor);
glColor4f(0.0f,0.0f,0.0f,1.0f); // Outline Color
for (S32 i=0; i<primitives.size(); i++)
{
TSDrawPrimitive & draw = primitives[i];
AssertFatal(draw.matIndex & TSDrawPrimitive::Indexed,
"TSMesh::render: rendering of non-indexed meshes no longer supported");
S32 drawType = getDrawType(draw.matIndex>>30);
glDrawElements(drawType,draw.numElements,GL_UNSIGNED_SHORT,&indices[draw.start]);
}
glColor4fv(oldcolor);
if (old2dtex) glEnable(GL_TEXTURE_2D);
glDepthFunc(GL_LEQUAL);
glLineWidth(oldLineWidth);
glColor3f(1.0f,1.0f,1.0f);
glCullFace(GL_BACK);
glPolygonMode (GL_BACK, GL_FILL);
if (oldlighting) glEnable(GL_LIGHTING);
}
/* end cell shading*/
Terrains
in terrain/terrRender.cc
in TerrainRender::renderXFCache
void TerrainRender::renderXFCache()
{
U32 count = 0;
bool doOutline=Con::getBoolVariable("$Pref::renderOutline",true);
F32 oldLineWidth;
glGetFloatv(GL_LINE_WIDTH,&oldLineWidth);
F32 lineWidth=Con::getFloatVariable("$Pref::OutlineWidth",2);
while (count < mXFIndexCount)
{
U32 mode = mXFIndexBuffer[count];
U32 vertexCount = mXFIndexBuffer[count + 1];
// Cartoon Outline
if(doOutline)
{
glHint (GL_LINE_SMOOTH_HINT, GL_NICEST); // Use The Good Calculations
glEnable (GL_LINE_SMOOTH);
glPolygonMode (GL_BACK, GL_LINE);
glLineWidth(lineWidth);
glDisable(GL_CULL_FACE);
glColor3f(0.0f,0.0f,0.0f);
glDisable(GL_TEXTURE_2D);
glDrawElements(mode, vertexCount, GL_UNSIGNED_SHORT, mXFIndexBuffer + count + 2);
glEnable(GL_TEXTURE_2D);
glEnable(GL_CULL_FACE);
glLineWidth(oldLineWidth);
glPolygonMode (GL_BACK, GL_FILL);
glDrawElements(mode, vertexCount, GL_UNSIGNED_SHORT, mXFIndexBuffer + count + 2);
}
else
{
glDrawElements(mode, vertexCount, GL_UNSIGNED_SHORT, mXFIndexBuffer + count + 2);
}
// End Cartoon Outline
count += vertexCount + 2;
}
}
Terrain - ToonColors
in scenegraph\sceneLighting.cc
void SceneLighting::TerrainProxy::lightVector(LightInfo * light)
Replace this:
Point3F lightDir = light->mDirection;
With This:
Point3F lightDir;//= light->mDirection; lightDir.x = 0.001f; lightDir.y = 0.001f; lightDir.z = -80.0f;
Theres also an if else blocked (search for shadowed? to find it)
It should start like this:
if(height >= intHeight)
{
}
else{
}
Replace with this:
// Cell Shading
bool toonColors = Con::getBoolVariable("$Pref::toonColors",true);
bool shadowCheck = true;
if (!toonColors)
{
shadowCheck = height >= intHeight;
}
if(shadowCheck)//height >= intHeight) // non shadowed
{
U32 idx = (xmask + (ymask << blockShift)) << 2;
Point3F normal = pNormals[bi] * normTable[idx++];
normal += pNormals[binext] * normTable[idx++];
normal += pNextNormals[binext] * normTable[idx++];
normal += pNextNormals[bi] * normTable[idx];
normal.normalize();
nextHeightArray[y] = height;
F32 colorScale = -mDot(normal, lightDir);
if (colorScale < 0.0)
{
colorScale = 0.0;
}
if (toonColors)
{
col.red = 5.0 * colorScale;
col.green = 5.0 * colorScale;
col.blue = 5.0 * colorScale;
}
else
{
col += ambient + lightColor * colorScale * lightScale[lsi];
}
// End Cell Shading
}
else // Shadowed
{
nextHeightArray[y] = intHeight;
col += ambient;
}
Interiors
in interior/interiorRender.cc
in void Interior::render after:
if (smRenderMode != 0) {
PROFILE_START(IRO_DebugRender);
debugRender(pMaterials, instanceHandle);
PROFILE_END();
return;
}
add
//Cel-Shading outline
bool doOutline=Con::getBoolVariable("$Pref::Interior::renderOutline",false);
if (doOutline) {
F32 oldLineWidth=1;
glGetFloatv(GL_LINE_WIDTH,&oldLineWidth);
F32 lineWidth=Con::getFloatVariable("$Pref::Interior::OutlineWidth",2);
glLineWidth(lineWidth);
// Base textures
glBlendFunc(GL_ONE, GL_ZERO);
glDisable(GL_TEXTURE_2D);
glColor3f(0, 0, 0);
for (U32 i = 0; i < sgActivePolyListSize; i++) {
const Surface& rSurface = mSurfaces[sgActivePolyList[i]];
glBegin(GL_LINE_LOOP);
glVertex3fv(mPoints[mWindings[rSurface.windingStart]].point);
S32 skip = rSurface.windingStart + 1;
while (skip < (rSurface.windingStart + rSurface.windingCount)) {
glVertex3fv(mPoints[mWindings[skip]].point);
skip += 2;
}
skip -= 1;
while (skip > rSurface.windingStart) {
if (skip < (rSurface.windingStart + rSurface.windingCount))
glVertex3fv(mPoints[mWindings[skip]].point);
skip -= 2;
}
glEnd();
}
glEnable(GL_TEXTURE_2D);
glLineWidth(oldLineWidth);
//return;
}
//End cartoon outline
Preferences
The following are the required preferences that the code uses.
Cel-Shading: Render: Outline: (true/false)
$Pref::renderOutline = "true";
Cel-Shading: Render: Outline: Size: (0-10)
$Pref::outlineWidth = "3";
Cel-Shading: Render: Outline: Interiors: (true/false)
$Pref::Interior::renderOutline = "true";
Cel-Shading: Render: Outline: Interiors: Size: (0-10)
$Pref::Interior::outlineWidth = "3";
Cel-Shading: Render: ToonColors: (true/false)
$Pref::toonColors = "true";



