[SOLVED] entities with different materials

.overlord.

28-12-2007 20:24:56

Hi,

I have a single mesh, but am using different materials
with my entities. when i add them to the BatchedGeometry
it builds the getFormatString() which pulls the materials off
the mesh but not the sub entities so it gets the original (mesh)
and not the entity materials. is this by design?

JohnJ

30-12-2007 03:35:47

getFormatString() which pulls the materials off the mesh but not the sub entities
Are you sure? getFormatString() here accepts a SubMesh*, and is called for every submesh of each mesh you use. I'm also using multi-material entities with PagedGeometry, and it works fine.

.overlord.

10-01-2008 18:34:04

hi,

if you use this code in the bottom half of World::load in example 1


//Load a tree entity
//Entity *myEntity = sceneMgr->createEntity("Tree", "tree2.mesh");

//////////////////////////////////////////////////////////////////////////

MaterialManager &matMgr = MaterialManager::getSingleton();
if(!matMgr.resourceExists("dummy"))
{
MaterialPtr pMaterial = matMgr.create("dummy", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
//pMaterial->setLightingEnabled(false);
//pMaterial->setSceneBlending(SBT_TRANSPARENT_ALPHA);
pMaterial->getTechnique(0)->getPass(0)->setAmbient(1,0,0);
}
if(!matMgr.resourceExists("other"))
{
MaterialPtr pMaterial = matMgr.create("other", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
//pMaterial->setLightingEnabled(false);
//pMaterial->setSceneBlending(SBT_TRANSPARENT_ALPHA);
pMaterial->getTechnique(0)->getPass(0)->setAmbient(0,1,0);
}

ManualObject* manual = 0;
manual = sceneMgr->createManualObject("MO");
manual->begin("dummy", RenderOperation::OT_TRIANGLE_LIST);

Ogre::Real x = 10;
Ogre::Real z = 10;

manual->position(0, 0, 0.0);
manual->textureCoord(0,0);
manual->normal(0,1,0);
manual->colour(ColourValue::White);

manual->position(x, 0, 0.0);
manual->normal(0,1,0);
manual->textureCoord(1,0);
manual->colour(ColourValue::White);

manual->position(x, 0, z);
manual->normal(0,1,0);
manual->textureCoord(1,1);
manual->colour(ColourValue::White);

manual->position(0, 0, z);
manual->textureCoord(0,1);
manual->normal(0,1,0);
manual->colour(ColourValue::White);

manual->quad(0,3,2,1);

manual->end();

manual->convertToMesh("MO-Mesh");
Entity *myEntity = sceneMgr->createEntity("dummyEnt", "MO-Mesh");
Entity *myEntity2 = sceneMgr->createEntity("otherEnt", "MO-Mesh");

myEntity2->setMaterialName("other");

//////////////////////////////////////////////////////////////////////////

//Setup the height function (so the Y values of trees can be calculated when they are placed on the terrain)
HeightFunction::initialize(sceneMgr);

//Randomly place 20,000 copies of the tree on the terrain
Vector3 position;
Radian yaw;
Real scale;
bool everyOther = true;
for (int i = 0; i < 20000; i++){
yaw = Degree(Math::RangeRandom(0, 360));

position.x = Math::RangeRandom(0, 1500);
position.z = Math::RangeRandom(0, 1500);
position.y = HeightFunction::getTerrainHeight(position.x, position.z);

scale = Math::RangeRandom(0.5f, 0.6f);

//treeLoader->addTree(myEntity, position, yaw, scale);
everyOther = !everyOther;
treeLoader->addTree(everyOther ? myEntity : myEntity2, position, yaw, scale);
}

Vector3 pos = camera->getPosition() - Vector3(0,0, 5);
pos.y = HeightFunction::getTerrainHeight(pos.x, pos.z) + 1;

Entity * e = sceneMgr->createEntity("ASingleOne", "MO-Mesh");
e->setMaterialName("other");
sceneMgr->getRootSceneNode()->createChildSceneNode(pos)->attachObject(e);
}


you'll see what happens. it should put a red / green every other tree
but they're all red. i placed a single green at the end to show
that just adding it in a traditional way works.

.overlord.

10-01-2008 18:35:11

also noticed that if your entity is named with an invalid char in
it like ":" the impostor images won't work since it can't make
an image with that char in the filename (on windows)

JohnJ

11-01-2008 15:31:51

Ok, I'll test this and hopefully find what's going on.

JohnJ

17-01-2008 02:42:06

You're right - instead of handling materials on a per-subentity basis, the current BatchPage and ImpostorPage system handles them on a per-submesh basis, which is obviously problematic when you use the same mesh with different materials.

I fixed the problems (including the filename impostor saving issue) and they're available from CVS now. If you don't have a CVS client you can wait for the next maintenance release (currently scheduled for Saturday).

.overlord.

17-01-2008 18:00:06

great! i'll check out from cvs now

thanks for the quick fix!

Jules Robichaud Gagnon

25-01-2008 17:29:55

If i understand well, it now generates impostors with all the sub entities materials added.

It generates very long texture name if we have several subentities. It crashes for us since we have lots of materials in our trees ( oFusion did not optimize the export of the tree ).

You might want to hash the "key" if it is not too expensive otherwise it can overflow the number of characters in some extreme cases.

Thanks to this though, it made me realize our trees were not optimized at all . We are gonna work on this...

JohnJ

26-01-2008 17:25:12

You might want to hash the "key" if it is not too expensive otherwise it can overflow the number of characters in some extreme cases.
Yeah, I didn't think of the name overflowing. I'll probably make it hash part of the filename if it's over a certain length (though I hope there aren't any hash collisions, although I guess the chances of that should be low).

Demon Lord

26-01-2008 21:08:36

I added a poor man's hash to the generateEntityKey function:

String ImpostorBatch::generateEntityKey(Entity *entity)
{
StringUtil::StrStreamType entityKey;
entityKey << entity->getMesh()->getName();
for (uint i = 0; i < entity->getNumSubEntities(); ++i){
entityKey << "-" << entity->getSubEntity(i)->getMaterialName();
}

String strKey( entityKey.str() );
char key[32] = {0};
unsigned int i = 0;
for (String::const_iterator it = strKey.begin(); it != strKey.end(); ++it)
{
key[i] ^= *it;
i = (i+1) % sizeof(key);
}
for (i = 0; i < sizeof(key); ++i)
key[i] = (key[i] % 26) + 'A';
return String(key, sizeof(key));
}


It seems good enough.

JohnJ

26-01-2008 23:51:09

Thanks - that works fine :). I added that to the official version, with one small change - I moved the hash generation into ImpostorTexture::renderTextures() since that's the only place it's needed (otherwise it would be calculating the hash for every tree of every page being loaded).