Loading mesh materials and textures

    This site uses cookies. By continuing to browse this site, you are agreeing to our Cookie Policy.

    • Loading mesh materials and textures

      Hello,

      I'm in the process of improving the D3DMeshNode9 from GCC4. It currently only uses the mesh portion of a DirectX .x file. I'm using Frank Luna's book (Introduction to 3D Game Programming With DirectX 9.0c) as a guide. My plan is to load the materials and textures of the subsets during D3DMeshNode9::VOnRestore and carry out the details of mesh rendering in the D3DMeshNode9::VRender.

      My quandary is when do I actually load the textures? Storing materials doesn't take up much space. Textures, on the other hand, do. Is it better to store a std::vector of textures as a std::string representation of their filename during the VOnRestore function and pull in the Resources during render? Or should the textures be stored as a std::vector of texture pointers (IDirect3DTexture9*)? Would there be much difference in processing time? Is there a third option?

      What are your thoughts?

      Thanks for weighing in.
      -Troy
    • Hello,

      jacktc wrote:

      My quandary is when do I actually load the textures? Storing materials doesn't take up much space. Textures, on the other hand, do. Is it better to store a std::vector of textures as a std::string representation of their filename during the VOnRestore function and pull in the Resources during render? Or should the textures be stored as a std::vector of texture pointers (IDirect3DTexture9*)? Would there be much difference in processing time? Is there a third option?


      I chose to load the texture in the VOnRestore function. One problem I'm running into is that the DirectX .x file assumes that the textures are stored in the same directory as the .x file. In GCC4 the .x files are stored in the Assets/Art/ directory. To load a resource using GCC4, you have to pass in the directory plus file name (i.e. Art/sometexture.dds). The default behavior of the .x reader is just the filename. Can anyone provide a clever way to load the resource from the Art directory without hardcoding "Art/" before texture file?

      Go Seahawks!
      -Troy
    • jacktc wrote:


      My quandary is when do I actually load the textures?

      It all depends. In my own engine, I have a resource manager that handles all resources. Objects that need a resource never actually hold onto the resource itself, they hold onto a proxy. The proxy may or may not be valid and any system that uses them needs to account for that. The most common case is that I ask for a texture (or whatever) and then immediately try to use it. This won't work because all resources are loaded on another thread and it's pretty unlikely it will have been loaded by then.

      Now, some resources are marked as volatile graphics resources. Whenever I lose Direct3D, I throw an event to the resource manager that will flush all of those resources. When Direct3D is restored, I send another message that restores all of those textures by reloading them. Again, this is done on another thread so when you alt+tab out of my game and alt+tab back in, the textures will briefly flicker as they pop back in.


      Storing materials doesn't take up much space. Textures, on the other hand, do. Is it better to store a std::vector of textures as a std::string representation of their filename during the VOnRestore function and pull in the Resources during render? Or should the textures be stored as a std::vector of texture pointers (IDirect3DTexture9*)? Would there be much difference in processing time? Is there a third option?

      In my engine, all resources are stored in a hash table. The key is a ResourceId and the data is a ResourceContainer, which is an object that contains the resource itself as well as extra data for status, ref count, etc. The ResourceId is typedef'ed to a StringId, which is a class I wrote that highly optimizes string compares. StringId's are basically strings under the covers, but comparing two StringId's is O(1) instead of O(n).

      jacktc wrote:


      Can anyone provide a clever way to load the resource from the Art directory without hardcoding "Art/" before texture file?

      In my data definitions for a game object, I do put the art path. For example:

      Source Code

      1. textureId = "textures/trees/treetest_03.png",


      This doesn't really bother me because my resources are all generic. I suppose I could look at the file extension, figure out it's a texture, and then prepend "texture/" to it, but that doesn't really make sense. .lua files are a perfect example; sometimes they're script files, something they're object definition files, and sometimes their tuning files.

      Of course, it goes a bit further than this. I have one directory called data (or whatever I want; it's tunable) and under that directory are all the sub directories for different levels. Each level is its own directory tree with its own data. There is one special level called global which contains data that is always available. It's important to note that caveat; it's the data that's available, not necessarily loaded.

      In the release version of the game, each sub-directory under data is a separate zip file.

      Hope that helps. Let me know if you want any extra clarification.

      -Rez
    • Thanks Rez! It looks like we're both burning the midnight oil :sleeping: .

      You've shared with me some cool ideas and slick tricks that I'll look into during the optimization/improvement phase. AKA: "If time allows or performance suffers." Sometimes you just got to do it first and then see if you need to improve it.

      I'm currently working on bringing skinned skeletal meshes into GCC4. One thought I had was to place the texture files in the same folder as the .x file. And then parse out the directory string from the .x file string (i.e. Art/skinnedmesh.x) to be prepended to the texture file names pulled from the .x file. Just to make it a little more flexible. For now, I just prepend 'Art/' to all my textures.

      This is some fun stuff! :thumbsup:

      Thanks!
      -Troy

      The post was edited 1 time, last by jacktc ().

    • You can't really be a game programmer without burning the candle on both ends. ;)

      -Rez

    • StringId's are basically strings under the covers, but comparing two StringId's is O(1) instead of O(n).

      I'm curious - how did you go about this? Is the length of the StringId's limited? Are they pooled globally? Or is there some other
      kind of trick to achieve this?



      Sometimes you just got to do it first and then see if you need to improve it.

      Isn't that always the case? Premature optimization is the root of all evil, after all ;)
    • Dendra wrote:

      Isn't that always the case? Premature optimization is the root of all evil, after all


      Agreed! Sometimes I spend too much time thinking about optimizing a solution rather than just throwing some code down.

      Dendra wrote:

      I'm curious - how did you go about this? Is the length of the StringId's limited? Are they pooled globally? Or is there some other
      kind of trick to achieve this?


      I wonder what Rez did?

      I might try to use some sort of hashing algorithm that turns a string into a 32- or 64-bit integer and use the integer for comparisons.
      -Troy
    • Dendra wrote:


      I'm curious - how did you go about this? Is the length of the StringId's limited? Are they pooled globally? Or is there some other
      kind of trick to achieve this?


      My StringId class looks a little like this:

      Source Code

      1. class StringId
      2. {
      3. const static std::string INVALID_STRING; // the string used when the StringId is invalid; note that this is not stored in the map
      4. const std::string* m_pData; // this is guaranteed to always point to a valid string
      5. static StringIdMap s_stringIdSet; // set of all StringId's
      6. public:
      7. // public interface here....
      8. };


      The idea is that the actual strings used across all string ids are stored in the static set. The instance just stores a pointer to that string. String ids can be constructed from other string ids or from actual strings. Constructing a string id from a string is a bit slow; it looks like this:

      Source Code

      1. void StringId::FindOrCreateStringId(const std::string& str)
      2. {
      3. auto findIt = s_stringIdSet.find(str);
      4. if (findIt != s_stringIdSet.end())
      5. m_pData = &(*findIt);
      6. else if (str == INVALID_STRING)
      7. m_pData = &INVALID_STRING;
      8. else
      9. m_pData = &(*s_stringIdMap.insert(str).first); // insert() returns a pair where the first value is an iterator pointing to the data item just inserted
      10. }


      Comparisons are lightning fast:

      Source Code

      1. bool StringId::operator==(const StringId& right) const
      2. {
      3. return (m_pData == right.m_pData); // this is just a pointer compare
      4. }


      So basically I'm trading construction speed and maybe some memory (though not necessarily) for comparison speed. I use StringIds is places where that trade-off makes sense.

      -Rez
    • jacktc wrote:



      I might try to use some sort of hashing algorithm that turns a string into a 32- or 64-bit integer and use the integer for comparisons.


      I am almost certain that this would result in disaster, unless you limit the length of the strings, since you will get hash collisions for sure.
      However, I used a similar approach for my custom string class once - they store their hash code (which is computed only once) and
      this hash code will be used for comparing two strings - only when the hash codes are equal, the actual strings are compared.
      The reason for this was not so much to speed up comparing two strings, but much more to speed up inserting them into hash tables, which is why I used
      that class as keys. Compared to the pooling approach, it uses less memory, but comparing two strings is of course still more costly.

      rezination wrote:


      The idea is that the actual strings used across all string ids are stored in the static set. The instance just stores a pointer to that string. String ids can be constructed from other string ids or from actual strings. Constructing a string id from a string is a bit slow; it looks like this:

      This is exactly what I had in mind when I mentioned pooling.It sure seems like a winning tradeoff in most cases, as I doubt one would often construct new strings during the main loop,
      but much rather when loading a new level or other stuff. Thanks for the extensive explanation!
    • Dendra wrote:

      jacktc wrote:



      I might try to use some sort of hashing algorithm that turns a string into a 32- or 64-bit integer and use the integer for comparisons.


      I am almost certain that this would result in disaster, unless you limit the length of the strings, since you will get hash collisions for sure.
      However, I used a similar approach for my custom string class once - they store their hash code (which is computed only once) and
      this hash code will be used for comparing two strings - only when the hash codes are equal, the actual strings are compared.
      The reason for this was not so much to speed up comparing two strings, but much more to speed up inserting them into hash tables, which is why I used
      that class as keys. Compared to the pooling approach, it uses less memory, but comparing two strings is of course still more costly.


      In Game Engine Architecture, Second Edition 2014; The author used hashing and only had 1 collision in his life so far, so i doubt it's that prone to collisions :)
    • ​In Game Engine Architecture, Second Edition 2014; The author used hashing and only had 1 collision in his life so far, so i doubt it's that prone to collisions


      At work we use string hashing for quite a few different things, I have never seen a collision myself either. I think depending on the algorithm you use, its possible that the only way you would really see a collision is if you were trying hard to see it, such as generating thousands of similar named strings. We also have a debug mode collision checker which will assert if another entry already carries the generated hash id, and has a different string. This is pre-processed out for release mode. Another thing to consider is that your hash strings are spread between multiple sets ie. you will never be checking if 'TransformComponent' is equal to 'GameplayState' as they are 2 different sets of id's, even if they share the same hashing class, so this also lowers the chance of collision.
      PC - Custom Built
      CPU: 3rd Gen. Intel i7 3770 3.4Ghz
      GPU: ATI Radeon HD 7959 3GB
      RAM: 16GB

      Laptop - Alienware M17x
      CPU: 3rd Gen. Intel i7 - Ivy Bridge
      GPU: NVIDIA GeForce GTX 660M - 2GB GDDR5
      RAM: 8GB Dual Channel DDR3 @ 1600mhz
    • Okay, I guess I should have clarified a bit more what I meant - I think it's not a good basis to compare strings that way in an engine,
      since if that engine is used a lot, there will be a collision at some point, and that could be quite a hard to trace bug.
      Of course you won't get collisions everywhere :)

      mholley519 wrote:


      We also have a debug mode collision checker which will assert if another entry already carries the generated hash id, and has a different string. This is pre-processed out for release mode.

      That is a pretty good idea! I guess doing it that way even makes the whole use-hash-code-for-equality-test-thingy safe. Wow :)