TGEA Color Tinting Shadergen Addition
by J.C. Smith · 03/06/2008 (11:38 am) · 10 comments
This modification will allow you to add ColorTinting to TGEA's shadergen material system. This is deal for RPGs in that it allows you to tint your armor or player skins to different colors without needing to use different textures. The performance impact is minimal, only adding one instruction to the pixel shader.
Most of the modifications occur in C++. They are:
in Shadergen/shaderfeature.cpp add this block of code near the end of the file:
Add this block of code to ShaderFeature.h:
in Materials/matinstance.cpp add this code near line 160 where all of the other shader features are added:
In materials/materials.h add this to the public area of the class:
In materials/materials.cpp around line 55 you should see this:
add these lines of code beneath it:
Then around line 140 in the InitPersistFields area add this:
then in the SetShaderConstants function find this line:
and add this beneath it:
In shadergen/featuremgr.cpp find this line:
and add this below it:
Finally, open up gfx/gfxstructs.h and find the line in the ShaderFeatureData enum that reads:
and add this below it:
That is all of the engine changes, so now let's set up a material to make sure that this works. Here's an example material which will shade the material red:
The tintColor[0] = "1.0 0.1 0.1 1.0"; line is where we specify a value to multiply our texture by. In this case it is set to 1.0 Red, 0.1 Green, 0.1 Blue and 1.0 Alpha. That will reduce the green and blue values to 10% of the original, while keeping the red color. To tint in other shaders simply modify the first three values of this line to whatever color variable you want. So long as the useTintColor isn't set to true for the current pass then no tinting will occur.
Enjoy!
Most of the modifications occur in C++. They are:
in Shadergen/shaderfeature.cpp add this block of code near the end of the file:
void UseTintColorFeat::processPix( Vector<ShaderComponent*> &componentList,
GFXShaderFeatureData &fd )
{
// grab connector texcoord register
ConnectorStruct *connectComp = dynamic_cast<ConnectorStruct *>( componentList[C_CONNECTOR] );
Var *tintColor = new Var;
tintColor->setType( "float4" );
tintColor->setName( "tintColor" );
tintColor->uniform = true;
tintColor->constNum = PC_USERDEF2;
Var *color = (Var*) LangElement::find( "col" );
MultiLine * meta = new MultiLine;
meta->addStatement( new GenOp( " @ *= @;\r\n",color,tintColor) );
output = meta;
}Add this block of code to ShaderFeature.h:
class UseTintColorFeat : public ShaderFeature
{
public:
virtual void processPix( Vector<ShaderComponent*> &componentList,
GFXShaderFeatureData &fd );
};in Materials/matinstance.cpp add this code near line 160 where all of the other shader features are added:
if ((i==GFXShaderFeatureData::UseTintColor) && (mMaterial->useTintColor[stageNum])) fd.features[i] = true;
In materials/materials.h add this to the public area of the class:
ColorF tintColor[MAX_STAGES]; bool useTintColor[MAX_STAGES];
In materials/materials.cpp around line 55 you should see this:
specular[i].set( 1.0, 1.0, 1.0, 1.0 );
add these lines of code beneath it:
tintColor[i].set( 1.0, 1.0, 1.0, 1.0 ); useTintColor[i] = false;
Then around line 140 in the InitPersistFields area add this:
addField("tintColor", TypeColorF, Offset(tintColor, Material), MAX_STAGES);
addField("useTintColor", TypeBool, Offset(useTintColor, Material), MAX_STAGES);then in the SetShaderConstants function find this line:
GFX->setVertexShaderConstF( VC_MAT_SPECPOWER, (float*)&specularPower[stageNum], 1 );
and add this beneath it:
GFX->setPixelShaderConstF( PC_USERDEF2, (float*)&tintColor[stageNum], 1 );
In shadergen/featuremgr.cpp find this line:
mFeatures[ GFXShaderFeatureData::BaseTex ] = new BaseTexFeat;
and add this below it:
mFeatures[ GFXShaderFeatureData::UseTintColor ] = new UseTintColorFeat;
Finally, open up gfx/gfxstructs.h and find the line in the ShaderFeatureData enum that reads:
BaseTex,
and add this below it:
UseTintColor,
That is all of the engine changes, so now let's set up a material to make sure that this works. Here's an example material which will shade the material red:
new Material(body0mat)
{
baseTex[0] = "~/data/shapes/character/textures/body/body1.dds";
tintColor[0] = "1.0 0.1 0.1 1.0";
useTintColor[0] = true;
};The tintColor[0] = "1.0 0.1 0.1 1.0"; line is where we specify a value to multiply our texture by. In this case it is set to 1.0 Red, 0.1 Green, 0.1 Blue and 1.0 Alpha. That will reduce the green and blue values to 10% of the original, while keeping the red color. To tint in other shaders simply modify the first three values of this line to whatever color variable you want. So long as the useTintColor isn't set to true for the current pass then no tinting will occur.
Enjoy!
#2
To do that you'd have to modify your custom pixel shader and add this to the Incoming ConnectData:
and then add this to your shader, after you have the diffusecolor into OUT.col but before you do any lighting, specular, normal mapping etc or other calculations:
03/02/2008 (1:28 am)
If your using a custom material you could pass the value to your shader in the same way by placing the GFX->setPixelShaderConstF( PC_USERDEF2, (float*)&tintColor[stageNum], 1 ); line into the custommaterial.cpp in the same area (in SetShaderConstants). But since you'd be using a custom shader then you'd have to modify your shader to multiply your diffusecolor by the value. To do that you'd have to modify your custom pixel shader and add this to the Incoming ConnectData:
uniform float4 tintColor : register(C7),
and then add this to your shader, after you have the diffusecolor into OUT.col but before you do any lighting, specular, normal mapping etc or other calculations:
OUT.col *= tintColor;
#3
03/06/2008 (2:33 pm)
Most cool. i'll use this to add variety to enemy monsters.
#4
Yet.
Right?
03/06/2008 (4:11 pm)
I just realized that this is great for changing a material, but each object uses the global material, so you couldn't do per-object tinting as such.Yet.
Right?
#5
03/07/2008 (6:20 pm)
You could just use setskin and have the material names as the changed material name. You'll need to make a material for each color variation but then could setskin between the materials for any shapebase object. That requires your object to have a base.name label for its texture, of course. That's how I do it in The Repopulation though. There are about 15 texture sets currently for the NPCs in game, but only about 6 actual textures. The rest are alternate materials with a tint applied and we just setskin based on which set to use.
#6
03/11/2008 (9:17 am)
Right, so having users, say, pick a ColorF value out of a color picker is no good unless the tinted materials are predefined. Still very good for cutting down texture usage I think, it seems like the video memory footprint is the same.
#7
03/11/2008 (7:24 pm)
Yeah, the tinted colors all have to be defined already, unfortunately. I'm using it for armor tinting (pre-defined colors) and for skin coloring. Rather than giving them a traditional color picking GUI though it simply gives a list of pre-defined body tones to choose from.
#8
03/12/2008 (10:23 am)
tdn.garagegames.com/wiki/Per-Object_Instance_Examples <-synergy. bit buisy atm, so could take a bit to incorporate the two at this end. If you want to update it yourself, well, thats the whole point to a wiki, eh?
#9
03/20/2008 (2:18 am)
On a sidenote, this code is now obsolete if you have TGEA 1.7. It is basically in the 1.7 release now, but it is named ColorMultiply rather than ColorTinting, which is probably a more suitable name. Same functionality though.
#10
06/28/2009 (7:42 pm)
Sorry, but how do you actually TINT the material? Mine's just a solid color when I do the ColorMultiply thing.
Torque 3D Owner Steven Chiu