Damage Texture with Transparency
by Derk Adams · 08/03/2009 (9:37 am) · 2 comments
Title:
Damage Texture with Transparency
Purpose:
This resource adds a single texture to the shapeBase object that is a second render with transparency based on damage level.
Background:
A damage layer has been a feature lacking from TGE. As such many types of solutions have been developed. Since none provided exactly what I needed, I created this resource.
Discussion:
A second texture file using the same UV map as the object's original texture is needed. It should represent the completely destroyed object. Two variables and associated functions are added to ShapeBase, one to load the texture and another to track the level of transparency. It is not intrinsically tied to the damage level in the engine, but could be.
The damage texture is a second render and as such, may slow screen draws. It should be minimal unless there are many double rendered objects on the screen. I tried to implement the ability as high as possible in the rendering pipeline so I didn't have to figure out as much of the rendering engine. It should be possible to implement this ability as a single rendering pass using openGL blending and I'd be interested if someone is able to do that.
Acknowledgements:
The ideas come from far and wide, and although I ended up modeling after the cloak texture, here are some resources that I explored before doing it myself.
Combining Multiple Texture Layers
Blended texture layer on models
Plastic Gem #33: Damaged/Bloody Weapons
Key:
I use the same indication of modifications as a patch file. A line beginning with a "-" is to be removed and a line beginning with a "+" is to be added. Be sure to remove the "+" when you actually put the line into your code. A few lines around the changes are shown to give context to the changes. The triple dot "..." is showing that information has been removed for brevity purposes.
Development Environment:
July 2009
Head 1.5.2
Win32
Single Player
Implementation:
EngineFile: /game/shapebase.h
EngineFile: /game/shapeBase.cc
In your object datablock, add the line:
Credits:
Derk Adams - adamsderk@hotmail.com
Damage Texture with Transparency
Purpose:
This resource adds a single texture to the shapeBase object that is a second render with transparency based on damage level.
Background:
A damage layer has been a feature lacking from TGE. As such many types of solutions have been developed. Since none provided exactly what I needed, I created this resource.
Discussion:
A second texture file using the same UV map as the object's original texture is needed. It should represent the completely destroyed object. Two variables and associated functions are added to ShapeBase, one to load the texture and another to track the level of transparency. It is not intrinsically tied to the damage level in the engine, but could be.
The damage texture is a second render and as such, may slow screen draws. It should be minimal unless there are many double rendered objects on the screen. I tried to implement the ability as high as possible in the rendering pipeline so I didn't have to figure out as much of the rendering engine. It should be possible to implement this ability as a single rendering pass using openGL blending and I'd be interested if someone is able to do that.
Acknowledgements:
The ideas come from far and wide, and although I ended up modeling after the cloak texture, here are some resources that I explored before doing it myself.
Combining Multiple Texture Layers
Blended texture layer on models
Plastic Gem #33: Damaged/Bloody Weapons
Key:
I use the same indication of modifications as a patch file. A line beginning with a "-" is to be removed and a line beginning with a "+" is to be added. Be sure to remove the "+" when you actually put the line into your code. A few lines around the changes are shown to give context to the changes. The triple dot "..." is showing that information has been removed for brevity purposes.
Development Environment:
July 2009
Head 1.5.2
Win32
Single Player
Implementation:
EngineFile: /game/shapebase.h
struct ShapeBaseData : public GameBaseData {
...
public:
...
StringTableEntry shapeName;
StringTableEntry cloakTexName;
+ StringTableEntry damageTexName;
...
class ShapeBase : public GameBase
{
...
protected:
...
/// @name Cloaking
/// @{
bool mCloaked;
F32 mCloakLevel;
TextureHandle mCloakTexture;
bool mHidden; ///< in/out of world
/// @}
+
+ /// @name Damaged
+ /// @{
+ F32 mDamagedLevel;
+ TextureHandle mDamagedTexture;
+ /// @}
...
public:
...
/// Returns level of cloaking, as it's not an instant "now you see it, now you don't"
F32 getCloakLevel();
/// @}
+ /// @name Damaged
+ /// @{
+ /// Sets the percent of damage on this object.
+ void setDamagedLevel(F32 damage);
+
+ /// Returns level of damage
+ F32 getDamagedLevel();
+ /// @}
...
}
...
inline F32 ShapeBase::getCloakLevel()
{
return(mCloakLevel);
}
+
+inline F32 ShapeBase::getDamagedLevel()
+{
+ return(mDamagedLevel);
+}
...EngineFile: /game/shapeBase.cc
ShapeBaseData::ShapeBaseData()
{
...
shapeName = "";
cloakTexName = "";
+ damageTexName = "";
...
void ShapeBaseData::initPersistFields()
{
...
addGroup("Render");
addField("shapeFile", TypeFilename, Offset(shapeName, ShapeBaseData));
addField("cloakTexture", TypeFilename, Offset(cloakTexName, ShapeBaseData));
+ addField("damageTexture", TypeFilename, Offset(damageTexName, ShapeBaseData));
addField("emap", TypeBool, Offset(emap, ShapeBaseData));
endGroup("Render");
...
void ShapeBaseData::packData(BitStream* stream)
{
...
stream->writeString(shapeName);
stream->writeString(cloakTexName);
+ stream->writeString(damageTexName);
...
void ShapeBaseData::unpackData(BitStream* stream)
{
...
shapeName = stream->readSTString();
cloakTexName = stream->readSTString();
+ damageTexName = stream->readSTString();
...
ShapeBase::ShapeBase()
{
...
mCloaked = false;
mCloakLevel = 0.0;
+ mDamagedLevel = 0.0;
...
bool ShapeBase::onAdd()
{
...
if (isClientObject())
{
if(mDataBlock->cloakTexName != StringTable->insert(""))
mCloakTexture = TextureHandle(mDataBlock->cloakTexName, MeshTexture, false);
+ if(mDataBlock->damageTexName != StringTable->insert(""))
+ mDamagedTexture = TextureHandle(mDataBlock->damageTexName, MeshTexture, false);
...
void ShapeBase::setDamageLevel(F32 damage)
{
if (!mDataBlock->isInvincible) {
F32 store = mDamage;
mDamage = mClampF(damage, 0.f, mDataBlock->maxDamage);
if (store != mDamage) {
updateDamageLevel();
if (isServerObject()) {
setMaskBits(DamageMask);
char delta[100];
dSprintf(delta,sizeof(delta),"%g",mDamage - store);
Con::executef(mDataBlock,3,"onDamage",scriptThis(),delta);
}
}
}
}
+
+void ShapeBase::setDamagedLevel(F32 damage)
+{
+ mDamagedLevel = mClampF(damage, 0.f, 1.f);
+ if (isServerObject())
+ setMaskBits(DamageMask);
+}
...
void ShapeBase::renderImage(SceneState* state, SceneRenderImage* image)
{
...
mShapeInstance->setupFog(fogAmount,state->getFogColor());
mShapeInstance->animate();
mShapeInstance->render();
+ // If damaged do a second render with transparency
+ if (mDamagedLevel != 0.0) {
+ glMatrixMode(GL_TEXTURE);
+ glPushMatrix();
+
+ glMatrixMode(GL_MODELVIEW);
+
+ F32 oldAlpha = mShapeInstance->getAlphaAlways();
+ mShapeInstance->setAlphaAlways(mDamagedLevel);
+ mShapeInstance->setOverrideTexture(mDamagedTexture);
+ mShapeInstance->render();
+ glMatrixMode(GL_TEXTURE);
+ glPopMatrix();
+
+ mShapeInstance->clearOverrideTexture();
+ mShapeInstance->setAlphaAlways(oldAlpha);
+ }
+
mShapeInstance->setEnvironmentMapOn(false, 1.0);
...
U32 ShapeBase::packUpdate(NetConnection *con, U32 mask, BitStream *stream)
{
...
if (stream->writeFlag(mask & DamageMask)) {
stream->writeFloat(mClampF(mDamage / mDataBlock->maxDamage, 0.f, 1.f), DamageLevelBits);
stream->writeInt(mDamageState,NumDamageStateBits);
stream->writeNormalVector( damageDir, 8 );
+ stream->writeFloat( mDamagedLevel, 8);
}
...
void ShapeBase::unpackUpdate(NetConnection *con, BitStream *stream)
{
...
if (stream->readFlag()) {
mDamage = mClampF(stream->readFloat(DamageLevelBits) * mDataBlock->maxDamage, 0.f, mDataBlock->maxDamage);
DamageState prevState = mDamageState;
mDamageState = DamageState(stream->readInt(NumDamageStateBits));
stream->readNormalVector( &damageDir, 8 );
if (prevState != Destroyed && mDamageState == Destroyed && isProperlyAdded())
blowUp();
updateDamageLevel();
updateDamageState();
+ mDamagedLevel = (stream->readFloat(8));
}
...
ConsoleMethod( ShapeBase, setDamageLevel, void, 3, 3, "(float level)")
{
object->setDamageLevel(dAtof(argv[2]));
}
+
+ConsoleMethod( ShapeBase, setDamagedLevel, void, 3, 3, "(float level)")
+{
+ object->setDamagedLevel(dAtof(argv[2]));
+}
...ScriptIn your object datablock, add the line:
damageTexture = "location of your file";In your damage script add something like:
%level = %obj.damagelevel / %obj.originallevel; %obj.setDamagedLevel(%level);
Credits:
Derk Adams - adamsderk@hotmail.com
About the author
Recent Blogs
• Projectile Spread• Plan for Derk Adams
• Continuous Laser
• Plan for Derk Adams
• Plan for Derk Adams
#2
Good to see resources still coming out for TGE.
08/03/2009 (10:00 pm)
interesting resource. will have to look at possibly porting it to tgea. Good to see resources still coming out for TGE.

Torque Owner CSMP
MP Studios
Thanks Derk.