Horde3D
http://horde3d.org/forums/

changing textures w/ h3dFindResElem/h3dSetResParamI [SOLVED]
http://horde3d.org/forums/viewtopic.php?f=2&t=1110
Page 1 of 1

Author:  philipppixel [ 28.02.2010, 19:01 ]
Post subject:  changing textures w/ h3dFindResElem/h3dSetResParamI [SOLVED]

Hi all,

I work now a little while with Horde3D and it's a great framework. But a thing I could not get working is to replace a model texture in-situ. Although I follow the instructions given here: http://www.horde3d.org/wiki/index.php5?title=Horde3D_Wiki:HOWTO and here: http://www.horde3d.org/forums/viewtopic.php?f=1&t=923, I just fail at making it work. I take this fails mainly because the API is unclear in that point, and I do calls with wrong parameters or sth.

This is what I do at class creation time:

Code:
_modelRes = h3dAddResource(H3DResTypes::SceneGraph, "models/man/man.scene.xml", 0);
//load alternative texture
_tex2 = h3dAddResource(H3DResTypes::Texture, "models/man/civil02.jpg", 0);
bool loaded = h3dutLoadResourcesFromDisk(::Values::CONTENT_DIR);
if(! loaded) std::cout << "could not load enemy ressources" << std::endl;


later then, in a certain condition, I want to exchange the texture

Code:
int idx = h3dFindResElem(_modelRes, H3DMatRes::SamplerElem, H3DMatRes::SampNameStr, "albedoMap");
H3DRes texRes  = h3dGetResParamI(_modelRes, H3DMatRes::SamplerElem, idx, H3DMatRes::SampTexResI);
std::cout << "found index " << idx << " tex2 is " << _tex2 << std::endl; //idx yields always -1
h3dSetResParamI(texRes, H3DMatRes::SamplerElem, idx, H3DMatRes::SampTexResI, _tex2);


As in the code denoted, h3dFindResElem() returns always -1, which seems to state sth. like "not found". The current texture keeps the same. The EngineLog doesn't show any errors beside these, although I just don't call h3dGetResElemCount() in my code.

Code:
5.794   Invalid elem in h3dGetResElemCount
5.794   Invalid elem or param in h3dGetResParamI
5.795   Invalid resource handle in h3dSetResParamI


can anyone help here?

Thanks in advance

edit: I am using Horde3D from SF in Revision 213, which must be Version 1 Beta 4

Author:  Volker [ 28.02.2010, 23:33 ]
Post subject:  Re: changing textures with h3dFindResElem and h3dSetResParamI

Based on your variable names I guess you are querying a Material param (sampler) from a model resource. That won't work. Instead you have to specify the material resource handle.

Author:  philipppixel [ 01.03.2010, 19:47 ]
Post subject:  Re: changing textures with h3dFindResElem and h3dSetResParamI

Hi Volker, thanks for the quick reply. I'm going to try that.

Author:  philipppixel [ 01.03.2010, 21:40 ]
Post subject:  Re: changing textures with h3dFindResElem and h3dSetResParamI

Hi all,

I just wanted to share the code that worked for me. Since Google didn't find any similar code on the interweb, I post it here for community's reference. Again: I intend to dynamically change the UV Map (aka albedo map) of the Chicago guy. If you look into the model scene definition "man.scene.xml" you will find a structure like this (I abbreviated for clarity's sake):

Code:
<Model name="man" geometry="models/man/man.geo" otherAttributesgohere>
   <!-- lots of "Join" elements here -->
   <Mesh name="body" lodLevel="1" material="models/man/civilian1.material.xml" otherAttributesgohere/>
   <Mesh name="body" material="models/man/civilian1.material.xml" otherAttributesgohere />
   <Mesh name="body" lodLevel="2" material="models/man/civilian1.material.xml" otherAttributesgohere />
   <Mesh name="body" lodLevel="3" material="models/man/civilian1.material.xml" otherAttributesgohere />
</Model>


This is a scene model with four meshes of which I'd like to access the second one. The mash's associated material "civilian1.material.xml" looks like this (again abbreviated):

Code:
<Material>
   <Shader source="shaders/model.shader" />
   <!-- here go shader flags -->
   <Sampler name="albedoMap" map="models/man/civil01.jpg" />
</Material>


Slowly I arrive at my target :). The sampler called "albedoMap" points to the texture "models/man/civil01.jpg", which I really, really like to exchange by a different UV map, located at "models/man/civil02.jpg". That second UV map needs necessarily to have the exact proportions as the first one since I don't change any model data. To be exact, I just copy-edited the JPG under a new name.

So and here is what I do in my program code:

Code:
//earlier I  load the second texture like this
_tex2 = h3dAddResource(H3DResTypes::Texture, "models/man/civil02.jpg", 0);
...
//get the mesh element from the scene model
H3DNode mesh = h3dGetNodeChild(_model, 1); //starting at zero, access the second mesh
//access the mesh's material
int meshMaterial = h3dGetNodeParamI(mesh, H3DMesh::MatResI);
//get the the ressource index for the UV map
int idx = h3dFindResElem(meshMaterial, H3DMatRes::SamplerElem, H3DMatRes::SampNameStr, "albedoMap");
//pull the texture ressource from the material by using the found index
H3DRes texRes  = h3dGetResParamI(meshMaterial, H3DMatRes::SamplerElem, idx, H3DMatRes::SampTexResI);
//set the 2nd texture back to the mesh material
h3dSetResParamI(meshMaterial, H3DMatRes::SamplerElem, idx, H3DMatRes::SampTexResI, _tex2);


Voilá, it is done. The only drawback is that all instances of that Chicago guy have now the second texture on themselves. To avoid this, cloning utilizing h3dCloneResource() is necessary, but until now I just fail to make it right.
Hope this helps, cheers

Author:  Volker [ 02.03.2010, 00:20 ]
Post subject:  Re: changing textures w/ h3dFindResElem/h3dSetResParamI [Solved]

Thanks for the sum up. Why is cloning the material not working? What did you do?

Author:  philipppixel [ 02.03.2010, 08:36 ]
Post subject:  Re: changing textures w/ h3dFindResElem/h3dSetResParamI [Solved]

It's been a pleasure to make the sum up. I just recall to search the web for an actual example.

Well, I believe that the failure to clone is again my fault, understanding the mechanics of H3D in that part. Anyways I'll post some code tonight. Perhaps I miss an important part again.

cheers

Author:  philipppixel [ 03.03.2010, 19:17 ]
Post subject:  Re: changing textures w/ h3dFindResElem/h3dSetResParamI [Solved]

Volker wrote:
Thanks for the sum up. Why is cloning the material not working? What did you do?


Hi, finally I managed to get my hands on the code again... In order to have only one Chicago guy changed (frankly, that guy needs a name. I call him... Buster) I use this Code:

Quote:
H3DRes modelResNew = h3dCloneResource(_modelRes, "");
std::cout << "old modelRes " << _modelRes << std::endl;
std::cout << "cloned modelRes " << modelResNew << std::endl;

h3dRemoveNode(_model);
_model = h3dAddNodes(H3DRootNode, modelResNew);
std::cout << "new model" << _model << std::endl;

//overwrite member for latter access
_modelRes = modelResNew;

//here starts the code posted at 02.03.2010
//get the mesh element from the scene model
H3DNode mesh = h3dGetNodeChild(_model, 1); //starting at zero, access the second mesh


I try to clone the original Model resource since there is only one cloning method which expects an H3DRes. Then I remove the model from the world. In turn I add a new model with the changed model resource. Finally I overwrite the model resource because I may want to change it again. Then I proceed fetching the mesh as I showed in my earlier post.

Nevertheless, the debug prints in the above code give the following output, which definitely explain, why my I now have no model at all anymore:
Code:
old modelRes 132
cloned modelRes 0
new model0


Any ideas?

Author:  Volker [ 04.03.2010, 10:45 ]
Post subject:  Re: changing textures w/ h3dFindResElem/h3dSetResParamI

What is _modelRes? If it is a scene graph resource, it seems that we don't support cloning of scene graph resources currently. But for you purpose that isn't necessary anyway. Because you want to have one of the characters with a different texture you have to clone the material resource that references the texture and is used by the model and not the scene graph resource. Then you have to assign the cloned material resource to the mesh node (not resource) using

Code:
h3dSetNodeParamI( meshNode, H3DMesh::MatResI, clonedMaterialResource );


after that you can change the texture of the cloned material resource as you have done it already.

Author:  philipppixel [ 04.03.2010, 21:22 ]
Post subject:  Re: changing textures w/ h3dFindResElem/h3dSetResParamI

Volker wrote:
What is _modelRes? If it is a scene graph resource, it seems that we don't support cloning of scene graph resources currently. But for you purpose that isn't necessary anyway. Because you want to have one of the characters with a different texture you have to clone the material resource that references the texture and is used by the model and not the scene graph resource. Then you have to assign the cloned material resource to the mesh node (not resource) using

Code:
h3dSetNodeParamI( meshNode, H3DMesh::MatResI, clonedMaterialResource );


after that you can change the texture of the cloned material resource as you have done it already.


Hi Volker, thanks for the patience you brought. You are right, I tried to clone a scene graph resource. So I followed your advice with different sequences of when I set the material resource back to the mesh. Unfortunately there seems to be an change-all-textures-or-change-nothing in place ;) So I am very sorry if I bug you with this problem. Nevertheless I've put now debug prints to the statements and the values seem to me not unexpected. This is the code I used until now:

Code:
   //_texture2 = h3dAddResource(H3DResTypes::Texture, "models/man/civil02.jpg", 0);
   //_model = h3dAddResource(H3DResTypes::SceneGraph, "models/man/man.scene.xml", 0);
   //bool loaded = h3dutLoadResourcesFromDisk(::Values::CONTENT_DIR);

   //extract mesh from model scene graph
   H3DNode mesh = h3dGetNodeChild(_model, 1);
   std::cout << "found mesh " << mesh << std::endl;
   //extract mesh material from mesh
   int meshMaterial = h3dGetNodeParamI(mesh, H3DMesh::MatResI);
   std::cout << "found material " << meshMaterial << std::endl;

   //hey cloning works really :)
   H3DRes clonedMaterialResource = h3dCloneResource(meshMaterial, "");
   std::cout << "clone material " << clonedMaterialResource << std::endl;

   //set new material resource back to mesh
   h3dSetNodeParamI(mesh, H3DMesh::MatResI, clonedMaterialResource);
   //extract mesh material again: meshMaterialNew == clonedMaterialResource
   int meshMaterialNew = h3dGetNodeParamI(mesh, H3DMesh::MatResI);
   std::cout << "found materialnew " << meshMaterialNew << std::endl;

   //fetch index from mesh material
   int idx = h3dFindResElem(meshMaterialNew, H3DMatRes::SamplerElem, H3DMatRes::SampNameStr, "albedoMap");
   std::cout << "found index " << idx << std::endl; //index is 0
   //replace texture resource inside material resource
   h3dSetResParamI(meshMaterialNew, H3DMatRes::SamplerElem, idx, H3DMatRes::SampTexResI, _texture2);


This code yields in the following debug out:

Code:
found mesh 472
found material 146
clone material 181
found materialnew 181
found index 0


Given that index 0 is a proper first index I don't see why this code shouldn't work. Checking the EngineLog I don't find any warnings or errors in that term. Did I missed something again?

Since my deadline comes rushed up and in order to get things done I should try to switch material.xmls instead of textures (although this situation really bugs me).

cheers

Author:  Volker [ 04.03.2010, 23:04 ]
Post subject:  Re: changing textures w/ h3dFindResElem/h3dSetResParamI

I finally tested it myself and the following code added to the chicago sample worked for me:

Code:
        // after the initialization of the particles in crowd.cpp line 64
   Particle special = _particles.back();
   H3DRes manRes = h3dFindResource( H3DResTypes::Material, "models/man/civilian1.material.xml" );
   H3DRes newRes = h3dCloneResource( manRes, "newManRes" );
   H3DRes newTex = h3dAddResource( H3DResTypes::Texture, "models/man/civil01Special.jpg", 0 );
   h3dutLoadResourcesFromDisk( _contentDir.c_str() );
   h3dSetResParamI( newRes, H3DMatRes::SamplerElem, 0, H3DMatRes::SampTexResI, newTex );
   int i = 0;
   int childMesh = 0;
   while( ( childMesh = h3dGetNodeChild( special.node, i++ ) ) != 0 )
      h3dSetNodeParamI( childMesh, H3DMesh::MatResI, newRes );


I don't know why you commented your first lines where you load the additional texture, but apart from that, I guess one of the problems in your code is that you only change the mesh of one LOD. So your texture swap may be visible only if the corresponding LOD is active.

Attachments:
Sample.jpg
Sample.jpg [ 37.54 KiB | Viewed 21128 times ]

Author:  philipppixel [ 05.03.2010, 20:17 ]
Post subject:  Re: changing textures w/ h3dFindResElem/h3dSetResParamI

Volker wrote:
I finally tested it myself and the following code added to the Chicago sample worked for me:

- - - -x8 snip - -

I don't know why you commented your first lines where you load the additional texture, but apart from that, I guess one of the problems in your code is that you only change the mesh of one LOD. So your texture swap may be visible only if the corresponding LOD is active.


Wow, it worked and I didn't realize it! Please accept my apologies if I wasted your time. You have been very kind to test my code, for which I am very grateful. I understand that LOD stands for "Level of Detail". The lack of my understanding the LOD concept may play an important role here. I just wonder what the difference between all used LODs is then, because the used material.xml keeps the same? I take this has to do with that following parameters but that would certainly make an extra topic ;)

There is a simple answer why I commented the first three lines. I wanted to show of what kind the used variables are, also indicating that I use that code already elsewhere.
Attachment:
yoda-proceedsat.jpg

Author:  Volker [ 05.03.2010, 21:41 ]
Post subject:  Re: changing textures w/ h3dFindResElem/h3dSetResParamI

philipppixel wrote:
Wow, it worked and I didn't realize it! Please accept my apologies if I wasted your time. You have been very kind to test my code, for which I am very grateful. I understand that LOD stands for "Level of Detail". The lack of my understanding the LOD concept may play an important role here. I just wonder what the difference between all used LODs is then, because the used material.xml keeps the same?

Although in the sample every LOD has the same material, one could change it to realize e.g. smaller textures, shaders without skinning or some other faster but less beautiful material when having lower level of detail.

Author:  sellee [ 05.04.2010, 00:53 ]
Post subject:  python code

Code:
#change helmet texture
helmetTex = h3d.addResource(h3d.ResTypes.Texture,"models/knight/helmet.tga",0)
h3d.utils.loadResourcesFromDisk("Content")      
h3d.findNodes(self._knight, 'helmet', h3d.NodeTypes.Mesh)
helmet = h3d.getNodeFindResult(0)

matRes = h3d.getNodeParamI(helmet,h3d.Mesh.MatResI)
idx = h3d.findResElem(matRes,h3d.MatRes.SamplerElem,h3d.MatRes.SampNameStr,"albedoMap")
h3d.setResParamI(matRes, h3d.MatRes.SamplerElem, idx   ,h3d.MatRes.SampTexResI, helmetTex)

Page 1 of 1 All times are UTC + 1 hour
Powered by phpBB® Forum Software © phpBB Group
https://www.phpbb.com/