Dynamic Skins and Material Swap Issue
by game4Rest · in Torque 3D Professional · 10/30/2009 (11:20 pm) · 26 replies
I started discussion on this topic from here. But to catch with the changes, and as a response to a request, I decided to surmarize what I've been doing and ask some help.
Before I go any further, I'd like to make it clear that this worked OK just until T3D beta 4 release.Currently, according to the material instance's vertext format, it gives me different assertFatal messages.
In the TSMaterialList::setMaterial that I'm going to add below, when I chose to init matInst like this,
matInst->init(features, getGFXVertexFormat<GFXVertexPNT>()), it says that "Not enough room in the buffer for this data!".
But when I initilize it like this way, matInst->init(features, getGFXVertexFormat<GFXVertexPTTT>()),
it says that "Something went bad with ShaderGen. The normal should be already defined.".
If I comment out those assertFatal lines, I can see that skins are changed. But when I quit the game, as we can expect, it crashes my game hard.
It seems like it has something to do with shader thing. But I don't have enough knowledge about it. So anyone please let me know the cause of this problem and shed some light on me?
Thanks in advance.
Here goes code changes that I made to make original resource work in T3D 1.0.
In the source/ts/tsShapeInstance.h, after
And after
add this.
Next, at the end of source/ts/tsShapeInstance.cpp,
add this,
#ifndef _CUSTOMMATERIAL_H_
#include "materials/customMaterialDefinition.h"
#endif
//end:
[/code]
Still in the same file,after
Now let's move to the next file source/ts/tsMaterialList.cpp.
At first, add this line.
And then, add this problematic method.
In the source/T3D/shapeBase.h.
add this.
After
Add this,
Still in the same file, after
We're getting close to the end. Let's move to the source/T3D/shapeBase.cpp.
First of all, add this in the destructor of ShapeBase(ShapeBase::~ShapeBase()).
From now, we have to be cautious to make it work correctly.
Find the these lines in the packUpdate.
And find these lines.
In the same if clause, after
In the unpackUpdate, after
Add this.
At the end of file and these.
Now, open up file source/materials/materialList.h.
Find the member variable
It is protected. Move it to [bold]public[/bold].
Next, in the source/materials/materialDefinition.h.
After
Now, let's move to the correspondent source/materials/materialDefinition.cpp.
At the end of the file, add this.
We're almost at the end. Let's open up the file source/materials/customMaterialDefinition.h.
Add this
Finally, just one to add. Let's open up source/materials/customMaterialDefinition.cpp.
After
Add this.
That's all.
Before I go any further, I'd like to make it clear that this worked OK just until T3D beta 4 release.Currently, according to the material instance's vertext format, it gives me different assertFatal messages.
In the TSMaterialList::setMaterial that I'm going to add below, when I chose to init matInst like this,
matInst->init(features, getGFXVertexFormat<GFXVertexPNT>()), it says that "Not enough room in the buffer for this data!".
But when I initilize it like this way, matInst->init(features, getGFXVertexFormat<GFXVertexPTTT>()),
it says that "Something went bad with ShaderGen. The normal should be already defined.".
If I comment out those assertFatal lines, I can see that skins are changed. But when I quit the game, as we can expect, it crashes my game hard.
It seems like it has something to do with shader thing. But I don't have enough knowledge about it. So anyone please let me know the cause of this problem and shed some light on me?
Thanks in advance.
Here goes code changes that I made to make original resource work in T3D 1.0.
In the source/ts/tsShapeInstance.h, after
class SceneState;add this.
//HJ: dynamic skins and material swap
class DynamicSkinData
{
public :
Vector<StringTableEntry> mTextures; // texture layers to blend together
StringTableEntry mMaterialName;
StringTableEntry mSkinTag;
};
//end:And after
void reSkin( String newBaseName, String oldBaseName = String::EmptyString );
add this.
//HJ: dynamic skin and material swap void SetDynamicSkin(DynamicSkinData* data); //end:
Next, at the end of source/ts/tsShapeInstance.cpp,
add this,
//HJ: dynamic skins and material swap
void TSShapeInstance::SetDynamicSkin(DynamicSkinData* data)
{
//First, check if the skin tag(materialName) exsits in our matInstance list.
//if it doesn't we don't do anything as this is incorrect skin data.
//(can't replace a skin we don't have)
TSMaterialList* pMatList = getMaterialList();
S32 foundMatInstIndex = -1;
for(S32 j=0; j < pMatList->mMaterialNames.size(); j++)
{
const char* pName = pMatList->mMaterialNames[j];
if(pName == NULL)
continue;
if(0==dStricmp(pName, data->mSkinTag))
{
foundMatInstIndex = j;
break;
}
}
if(-1 == foundMatInstIndex)
return;
//Now check if the material mapped to this skin tag matches the one we want to map to it.
//if it does, then our work is already done and we can simply return
BaseMatInstance* matInst = pMatList->getMaterialInst(foundMatInstIndex);
Material* currentMat = NULL;
if (matInst) {
currentMat = dynamic_cast<Material*>(matInst->getMaterial());
}
Material *mat = dynamic_cast<Material*>( Sim::findObject(data->mMaterialName) );
if(mat)
{
//it's already mapped at the current material
if(mat == currentMat)
return;
//The material already exists. so lets just map it to this matInst/skin tag slot
pMatList->setMaterial(foundMatInstIndex, mat);
}
else
{
//Oh dear, the material doesn't exist. So we have to create it then map it to the matInst/skin
//tag slot.
//the trick to creating a new material is that we are going to copy the details of a
//"Template" material. The material we choose to copy is based on how many textures we are blending.
//If 3, then we choose the material that is set up to blend 3 textures, etc. That way designers can
//control EXACTLY how these materials operates without needing to recompile code.
S32 maxNumTextures = Con::getIntVariable("$pref::DynamicSkins::MaxBlendedTextures");
//Clamp the number of textures, for sanity sake
S32 numBlendedTextures = data->mTextures.size();
if(numBlendedTextures > maxNumTextures)
numBlendedTextures = maxNumTextures;
//Read the name of the desired material template from prefs
char materialTemplate[512];
dSprintf(materialTemplate, sizeof(materialTemplate), "$pref::DynamicSkins::MaterialTemplate_%d", numBlendedTextures);
const char* templateName = NULL;
templateName = Con::getVariable(materialTemplate);
//if we couldn't read the name, return
if(!templateName)
return;
//We're going for custom materials here. If players want normal materials that option will need to
//be added in code.
CustomMaterial* templateMat = dynamic_cast<CustomMaterial*>(Sim::findObject(templateName));
if(!templateMat)
return;
//We found it, so let's copy it
CustomMaterial* newMat = new CustomMaterial();
*newMat = *templateMat;
//Now change the variables we want on our copy.
newMat->assignName(data->mMaterialName);
//don't make the "mapTo" equal to the skin tag. We don't want all objects which have a "Head" texture(skin tag)
//using our dynamic material for instance. Then ALL of them would have the same material as "Head"
newMat->mMapTo = StringTable->insert(data->mMaterialName);
//replace textures
for(S32 i=0; i< data->mTextures.size(); i++)
newMat->mTexFilename[i] = data->mTextures[i];
AssertFatal(newMat->registerObject(), "Unable to register dynamic material!");
Sim::getRootGroup()->addObject(newMat);
pMatList->setMaterial(foundMatInstIndex, newMat);
}
}
Now open up file source/ts/tsShape.h.
Add this.
[code]
//HJ: dynamic skin and material swap
#ifndef _MATERIAL_H_
#include "materials/materialDefinition.h"
#endif #ifndef _CUSTOMMATERIAL_H_
#include "materials/customMaterialDefinition.h"
#endif
//end:
[/code]
Still in the same file,after
void push_back(const char * name, U32 flags, Material* mat);add this.
//HJ: dynamic skins and material swap bool setMaterial(U32 index, Material* newMat); //end:
Now let's move to the next file source/ts/tsMaterialList.cpp.
At first, add this line.
#include "materials/materialFeatureTypes.h" //HJ: beta 5. dynamic skins and material swap
And then, add this problematic method.
//HJ: dynamic skins and material swap
bool TSMaterialList::setMaterial(U32 index, Material* newMat)
{
if (index < 0 || index > mMaterials.size()) {
return false;
}
if ( newMat ) {
if (mMatInstList[index]->getMaterial() == newMat) {
return true;
}
// dump the old mat instance
if (mMatInstList[index]) {
delete mMatInstList[index];
}
mMatInstList[index] = NULL;
// change texture
CustomMaterial* cust = dynamic_cast<CustomMaterial*>(newMat);
String texPath;
if (cust) {
texPath = cust->mTexFilename[0];
} else{
texPath = newMat->mBaseTexFilename[0];
}
GFXTexHandle tex = GFXTexHandle(texPath, &GFXDefaultStaticDiffuseProfile, avar("%s() - NA (line %d)", __FUNCTION__, __LINE__));
if (!tex.isValid()) {
return false;
}
// change texture
mMaterials[index] = tex;
BaseMatInstance *matInst = newMat->createMatInstance();
mMatInstList[index] = matInst;
// GFX2_RENDER_MERGE
//HJ: changed from original to work with T3D
//fd.features[MFT_RTLighting] = true; //beta 5: commented out by deepscratch's solution
FeatureSet features = MATMGR->getDefaultFeatures();
//GFXVertexPNT *tsVertex = NULL;
features.addFeature( MFT_VertTransform );
features.addFeature( MFT_DiffuseMap );
features.addFeature( MFT_RTLighting);
features.addFeature(MFT_NormalMap);
features.addFeature( MFT_OverlayMap );
features.addFeature( MFT_DetailMap );
features.addFeature( MFT_DiffuseColor );
features.addFeature( MFT_ColorMultiply );
features.addFeature( MFT_AlphaTest );
features.addFeature( MFT_IsTranslucent );
//MaterialFeatureData fd;
//fd.features = features;
//fd.materialFeatures = features;
matInst->init(features, matInst->getVertexFormat());// getGFXVertexFormat<GFXVertexPTTT>() );
//end:
}
return true;
}
//end:I think the code right above is causing the problem that I have. But anyway, let's move to the next file.In the source/T3D/shapeBase.h.
add this.
//HJ: dynamic skins and material swap #ifndef _TSSHAPEINSTANCE_H_ #include "ts/tsShapeinstance.h" #endif //end: After this, [code] friend void physicalZoneFind(SceneObject*, void*);Add these.
//HJ: dynamic skins and material swap protected : Vector<DynamicSkinData> mDynamicSkins; void BuildDynamicSkins(); void ClearDynamicSkins(); //end:
After
SoundMaskN = Parent::NextFreeMask << 9,
Add this,
DynamicSkinMask = Parent::NextFreeMask << 10, //HJ: dynamic skins and material swap
Still in the same file, after
const char* getSkinName(); /// @}Add these methods.
//HJ: dyanmic skin and material swap void UpdateDynamicSkins(); bool AddDynamicSkinLayerTexture(const char* skinTag, const char* texture, const char* matName); bool ResetDynamicSkin(const char* skinTag, const char* texture, const char* matName); const char* getMeshTexture(StringTableEntry mesh); //HJ: get the texture name on the specified mesh. //end:
We're getting close to the end. Let's move to the source/T3D/shapeBase.cpp.
First of all, add this in the destructor of ShapeBase(ShapeBase::~ShapeBase()).
//HJ: Dynamic skins and material swap // make sure list cleaned up ClearDynamicSkins(); //end:
From now, we have to be cautious to make it work correctly.
Find the these lines in the packUpdate.
// mask off images that aren't updated
for(i = 0; i < MaxMountedImages; i++)
if(!mMountedImageList[i].dataBlock)
mask &= ~(ImageMaskN << i);Right after them, add these.//HJ: dynamic skins and material swap if(mDynamicSkins.size() == 0) mask &= ~DynamicSkinMask; else mask |= DynamicSkinMask; //end:
And find these lines.
// Group some of the uncommon stuff together. if (stream->writeFlag(mask & (NameMask | ShieldMask | HideCloakMask | InvincibleMask | SkinMask....Change it like this.
// Group some of the uncommon stuff together. if (stream->writeFlag(mask & (NameMask | ShieldMask | HideCloakMask | InvincibleMask | SkinMask | DynamicSkinMask //HJ: dynamic skins and material swap | MeshHiddenMask )))
In the same if clause, after
if (stream->writeFlag(mask & InvincibleMask)) {
stream->write(mInvincibleTime);
stream->write(mInvincibleSpeed);
}Add this.//HJ: dynamic skin and material swap
if(stream->writeFlag(mask & DynamicSkinMask))
{
// the number of dynamic skins
stream->writeInt(mDynamicSkins.size(), 10);
for(S32 x = 0; x < mDynamicSkins.size(); x++)
{
stream->writeString(mDynamicSkins[x].mSkinTag);
stream->writeString(mDynamicSkins[x].mMaterialName);
stream->writeInt(mDynamicSkins[x].mTextures.size(), 10);
for(S32 y = 0; y < mDynamicSkins[x].mTextures.size(); y++)
{
stream->writeString(mDynamicSkins[x].mTextures[y]);
}
}
}
//end:In the unpackUpdate, after
if (stream->readFlag())
{
// InvincibleMask
F32 time, speed;
stream->read(&time);
stream->read(&speed);
setupInvincibleEffect(time, speed);
}Add this.
//HJ: dynamic skins and material swapping
if(stream->readFlag())
{
ClearDynamicSkins();
// the number of dynamic skins
S32 numDynamicSkins = stream->readInt(10);
for(S32 x = 0; x < numDynamicSkins; x++)
{
DynamicSkinData data;
mDynamicSkins.push_back(data);
S32 index = mDynamicSkins.size() -1;
mDynamicSkins[index].mSkinTag = stream->readSTString();
mDynamicSkins[index].mMaterialName = stream->readSTString();
// the number of dynamic skins
S32 numDynamicTextures = stream->readInt(10);
for(S32 y = 0; y < numDynamicTextures; y++)
{
mDynamicSkins[index].mTextures.push_back(stream->readSTString());
}
}
BuildDynamicSkins();
}
//end:At the end of file and these.
//HJ: dynamic skins and material swap
const char* ShapeBase::getMeshTexture(StringTableEntry mesh) //HJ: Not included in the original resource. added for my special needs
{
if(!mesh)
{
return NULL;
}
//At first, we need to find the given mesh.
for(int i=0;i<mShapeInstance->getShape()->objects.size();i++)
{
S32 idx = mShapeInstance->getShape()->objects[i].nameIndex;
if(idx>=0)
{
if(0==dStricmp(mesh, mShapeInstance->getShape()->getName(idx))) //Found the mesh
{
TSMesh* iMesh = mShapeInstance->mMeshObjects[i].getMesh(0);
U32 material= iMesh->primitives[0].matIndex & TSDrawPrimitive::MaterialMask;
if(iMesh->primitives[0].matIndex & TSDrawPrimitive::NoMaterial)
{
Con::errorf("No material on this mesh");
return NULL;
}
else
{
TSMaterialList* materials = mShapeInstance->getShape()->materialList;
const char* matName = materials->getMaterialName(material);
return matName;
}
}
}
}
return NULL;
}
ConsoleMethod( ShapeBase, getMeshTexture, const char*, 3, 3, "(string meshname)")
{
return object->getMeshTexture(argv[2]);
}
void ShapeBase::BuildDynamicSkins()
{
for(S32 i = 0; i < mDynamicSkins.size(); i ++)
mShapeInstance->SetDynamicSkin( &mDynamicSkins[i]);
}
void ShapeBase::ClearDynamicSkins()
{
for(S32 i = 0; i < mDynamicSkins.size(); i++)
mDynamicSkins[i].mTextures.clear();
mDynamicSkins.clear();
}
void ShapeBase::UpdateDynamicSkins()
{
setMaskBits(DynamicSkinMask);
}
ConsoleMethod( ShapeBase, UpdateDynamicSkins, void, 2, 2, "")
{
object->UpdateDynamicSkins();
}
bool ShapeBase::AddDynamicSkinLayerTexture(const char* skinTag, const char* texture, const char* matName)
{
// for sanitys sake, lets prevent scripters from going crazy with skin layers.
if( mDynamicSkins.size() >= CustomMaterial::MAX_TEX_PER_PASS )
{
Con::errorf("AddDynamicSkinLayerTexture(): Max number of textures reached! (%d)", mDynamicSkins.size());
return false;
}
bool found = false;
for(S32 i = 0; i < mDynamicSkins.size(); i ++)
{
if(0 == dStricmp(mDynamicSkins[i].mSkinTag, skinTag))
{
found = true;
mDynamicSkins[i].mTextures.push_back( StringTable->insert(texture) );
mDynamicSkins[i].mMaterialName = StringTable->insert(matName);
}
}
if(!found)
{
DynamicSkinData data;
mDynamicSkins.push_back(data);
S32 index = mDynamicSkins.size() - 1;
mDynamicSkins[index].mTextures.clear();// redundant but lets just make sure.
mDynamicSkins[index].mTextures.push_back( StringTable->insert(texture) );
mDynamicSkins[index].mSkinTag = StringTable->insert(skinTag);
mDynamicSkins[index].mMaterialName = StringTable->insert(matName);
}
return true;
}
//--------------------------------------------------------------------------------------------------------
ConsoleMethod( ShapeBase, AddDynamicSkinLayerTexture, bool, 5, 5, "(string skinTag, string texture, string materialName)")
{
return object->AddDynamicSkinLayerTexture(argv[2],argv[3],argv[4]);
}
//--------------------------------------------------------------------------------------------------------
bool ShapeBase::ResetDynamicSkin(const char* skinTag, const char* texture, const char* matName)
{
if(!texture || !skinTag || !matName)
return false;
bool found = false;
for(S32 i = 0; i < mDynamicSkins.size(); i ++)
{
if(0 == dStricmp(mDynamicSkins[i].mSkinTag, skinTag))
{
found = true;
mDynamicSkins[i].mTextures.clear();
mDynamicSkins[i].mTextures.push_back( StringTable->insert(texture) );
mDynamicSkins[i].mMaterialName = StringTable->insert(matName);
}
}
if(!found)
{
DynamicSkinData data;
mDynamicSkins.push_back(data);
S32 index = mDynamicSkins.size() - 1;
mDynamicSkins[index].mTextures.clear();// redundant but lets just make sure.
mDynamicSkins[index].mTextures.push_back( StringTable->insert(texture) );
mDynamicSkins[index].mSkinTag = StringTable->insert(skinTag);
mDynamicSkins[index].mMaterialName = StringTable->insert(matName);
}
return true;
}
//--------------------------------------------------------------------------------------------------------
ConsoleMethod( ShapeBase, ResetDynamicSkin, bool, 5, 5, "(string skinTag, string texture, string materialName)")
{
return object->ResetDynamicSkin(argv[2], argv[3], argv[4]);
}
//end:Now, open up file source/materials/materialList.h.
Find the member variable
Vector<String> mMaterialNames;.
It is protected. Move it to [bold]public[/bold].
Next, in the source/materials/materialDefinition.h.
After
static void initPersistFields();Add this.
//HJ: dynamic skins and material swap Material &operator=(const Material &Material); //end:
Now, let's move to the correspondent source/materials/materialDefinition.cpp.
At the end of the file, add this.
//HJ: dynamic skins and material swap
Material & Material::operator =(const Material &material)
{
// tedious, but want to avoid copying simobject data, which a straight memcopy would do.
// if you do that you get the simobject ID and then it complains when you try to register it.
for (S32 i = 0; i < MAX_STAGES; i++) {
mBaseTexFilename[i] = material.mBaseTexFilename[i];
mDetailTexFilename[i] = material.mDetailTexFilename[i]; //HJ: mDetailFilename>>>mDetailTexFilename
mBumpTexFilename[i] = material.mBumpTexFilename[i]; //HJ: mBumpFileName>>>mBumpTexFilename
mEnvTexFilename[i] = material.mEnvTexFilename[i]; //HJ: mEnvFileName>>>mEnvTexFilename
mStages[i] = material.mStages[i];
mDiffuse[i] = material.mDiffuse[i];
mSpecular[i] = material.mSpecular[i];
mSpecularPower[i] = material.mSpecularPower[i];
mPixelSpecular[i] = material.mPixelSpecular[i];
//mVertexSpecular[i] = material.mVertexSpecular[i]; //HJ: commented out. deepscratch
mExposure[i] = material.mExposure[i];
mAnimFlags[i] = material.mAnimFlags[i];
mScrollDir[i] = material.mScrollDir[i];
mScrollSpeed[i] = material.mScrollSpeed[i];
mScrollOffset[i] = material.mScrollOffset[i];
mRotSpeed[i] = material.mRotSpeed[i];
mRotPivotOffset[i] = material.mRotPivotOffset[i];
mRotPos[i] = material.mRotPos[i];
mWavePos[i] = material.mWavePos[i];
mWaveFreq[i] = material.mWaveFreq[i];
mWaveAmp[i] = material.mWaveAmp[i];
mWaveType[i] = material.mWaveType[i];
mSeqFramePerSec[i] = material.mSeqFramePerSec[i];
mSeqSegSize[i] = material.mSeqSegSize[i];
mGlow[i] = material.mGlow[i];
mEmissive[i] = material.mEmissive[i];
mColorMultiply[i] = material.mColorMultiply[i];
}
mDoubleSided = material.isDoubleSided();
mCubemapName = material.mCubemapName;
mCubemapData = material.mCubemapData;
mDynamicCubemap = material.mDynamicCubemap;
mTranslucent = material.isTranslucent();
mTranslucentBlendOp = material.mTranslucentBlendOp;
mTranslucentZWrite = material.mTranslucentZWrite;
mAlphaTest = material.mAlphaTest;
mAlphaRef = material.mAlphaRef;
mPlanarReflection = material.mPlanarReflection;
mMapTo = material.mMapTo;
mIsIFL = material.isIFL();
mPath = material.getPath();
return *this;
}
//end:We're almost at the end. Let's open up the file source/materials/customMaterialDefinition.h.
Add this
//HJ: dynamic skins and material swap CustomMaterial &operator=( const CustomMaterial &Material); //end:just before this line.
DECLARE_CONOBJECT(CustomMaterial);
Finally, just one to add. Let's open up source/materials/customMaterialDefinition.cpp.
After
void CustomMaterial::onRemove().
Add this.
//HJ: dynamic skins and material swap
CustomMaterial & CustomMaterial::operator =(const CustomMaterial &material) {
Parent::operator =(material);
// custom material copy
for (S32 i = 0; i < MAX_TEX_PER_PASS; i++) {
mTexFilename[i] = material.mTexFilename[i];
mFlags[i] = material.mFlags[i];
}
if (NULL == material.mFallback) {
mFallback = NULL;
} else{
*mFallback = *material.mFallback;
}
//HJ: no need this
/*
if (NULL == material.mDynamicLightingMaterial) {
mDynamicLightingMaterial = NULL;
} else{
mDynamicLightingMaterial = material.mDynamicLightingMaterial;
}
if (NULL == material.mDynamicLightingMaskMaterial) {
mDynamicLightingMaskMaterial = NULL;
} else{
mDynamicLightingMaskMaterial = material.mDynamicLightingMaskMaterial;
}
*/
//end:
mVersion = material.mVersion;
mRefract = material.mRefract;
mMaxTex = material.mMaxTex;
ShaderData* sd = static_cast<ShaderData*>(Sim::findObject(material.mShaderDataName));
if ( sd ) {
mShaderData = sd;
}
mShaderDataName = material.mShaderDataName;
return *this;
}
//end:That's all.
About the author
Recent Threads
#22
I think the post had bug, you should upload your body again by editing your resource.
FYI, I saw it empty also.
03/27/2010 (9:26 am)
Seems strange I never seen anything about preview process.I think the post had bug, you should upload your body again by editing your resource.
FYI, I saw it empty also.
#23
03/27/2010 (11:45 am)
Sounds insteresting. I hope your resource will be available soon.
#24
03/28/2010 (3:48 am)
It works now. Thanks for your patience.
#26
04/07/2010 (10:54 pm)
Thank you!
Torque Owner game4Rest
colyd studio