   Engine material systems
  I am well aware that my graphics engine needs an overhaul for some things.At the moment, I'm concentrating on the material system. It's not really a system it's more like a bunch of objects that inherit from a single base class that just provides an interface.I want my system to be able to represent things from the lighting material for a particular object, to reflective surfaces.I know how to do some of the things individually, but I'm in the dark as to how to have a proper system that will take it all and where new materials can be added as simply as writing a new class.How have others done it?   
  I have a material class, which contains an ID, a name, some other data, and two member structs, one for Render properties and one for Physical properties.Render properties include the diffuse & normal map.  Physical properties include things like friction, etc.All materials in my game are the same class ( no inheritance ), rather, I have about 25 properties between the Phyiscal and Render structures to vary how the materials respond.For instance, I can make a material that has the same texture as a solid metal sheet material, but this one can be uncollidable.  I have some materials that are marked as not walkable, others that don't cast or receive shadows.I would recommend to not tie one material->one texture, or one material-> one shader.In my case the shader used is a function of the part of the lighting pipeline being used, all materials use the same shaders.   ;Quote:Original post by SimmerDI would recommend to not tie one material->one texture, or one material-> one shader.So, do you have a single shader and single texture associated with your material object? Or can you have a series of shaders and textures associated with a single material object?   ;  I have a rather complex material systemTtextures just represent the texture data.Materials combine different textures and effects.E.g.: You want a multi layered terrain with 4 textures, that has some special bullethit effects and maybe is covered by volumetric fogso you specify the layers and the effects as you see underneathEffects take care of the data that is required to render a certain effect( that is the maximum amount of different data that is required to render a certain effect, lower quality settings won t require all the data that is provided)The effect contains information about the sounds to play, the particles to spawn or what vertex/pixelshader to useEfx-objects describe certain effect possibilitiese.g.: which shaders it supports, which particle effects it can handle ...(use:...)where the efx-object plugin is( dll:...)and if there are efx-objects that can handle the same effect, the priority setting will determine which of these objects to use.This system allows you to extend your engine in any way you want to the whole rendering is done in the dlls.However you should think about how complex you want to make it. There s no need for such a complex system if you don t plan to use your engine for further projects. Mine currently is kept independent of the render of the engine so I can use it in the 3D editor and the 3d engine without code refactoring and it works pretty well.The text declarations of materials,effects,efx-objects are put into xml files to  load them in with tiny xml easilytexture:-texture datamaterial:- layer0: "sometexture"- layer1: "sometexture2"- layern: "sometexturen"- efx1 //graphic effect e.g.: n-layered terrain- efx2 //bullethit- efx3 //fog ....effect- id: efx1- use: nlayer_blendefx-object- type: graphics- dll: xyz.dll- can: nlayer_blend,4layer_blend .....- priority: 100   ;  Well, tomorrow, or rather, today (it is now the wee hours of the morning) I'll be making a couple of more attempts with the material system.Please, don't hesitate to keep the ideas (or info about your systems) coming. I've gotten really good info from SimmerD and Basiror both.   ;  Here is an example from my materials.txt configuration file. group cartskin1   {  int id = 1493;  float    flammability   = 0.0;  float    bouyancy  = 0.0;  float    stickiness= 0.0;   float    friction  = 1.0;  float    metallic  = 0.7;  float    reflectivity   = 1.0;  float    opacity   = 1.0;  float    dragCoefficent = 1.0;  float    solidity  = 5.0;  vector   specular = 1.8 1.6 1.5 1.0;  vector   emissive = 0.1 0.0 0.0 0.0;  vector   bump_scale = 1.0 1.0 0.6 0.0;  vector   spec_scale = 1.0 1.0 0.3 0.0;  vector   diffuse = 1.0 1.0 1.0 1.0;  vector   weights = 0.5 0.5 0.5 1.0;  vector   tex_scale = 0.25 0.25 0.25 0.25;  boolshadow_cast    = true;  boolshadow_receive = true;  boollight_receive  = true;  boolblocks_light   = true;  boolwalkable  = false;    booldeadly    = false;    string   sound = "metal";  string   debris = "sparks";  string   decal = "hole";    group layer  { int count = 1; group 0 {   string   diffuseMap =   "materials\cavecity\cartskin1.dds";string   normalMap  =   "materials\cavecity\cartskin1_bump.dds"; }  }    }Here an excerpt from my material.h header file.struct Material{  public :std::wstring mName;typedef uint16 ID;IDmID;   uint32 mFlags;enum{INVALID_ID= 0,   MaxNumLayers   = 4,   BlocksLight    = 0x1,   BlocksMovement = 0x2,   Liquid    = 0x4,   Deadly    = 0x8,Walkable  = 0x10,   ShadowRecv= 0x20,   ShadowCast= 0x40,   LightRecv = 0x80,   Any  = 0xffff};struct Physical{  float32 mFlammability;  float32 mBouyancy;  float32 mStickiness; // for arrows sticking in it  float32 mFriction;  float32 mMetallic;  float32 mReflectivity;  float32 mOpacity;  float32 mDragCoefficent; float32 mWalkability;float32 mSolidity;float32 mLayerMin;float32 mLayerMax;float32 mLayerMinDensity;float32 mLayerMaxDensity;  Material::ID mBurnTransitionMaterial;  // what material to become    };struct Render{   void Preload() const;   D3DXVECTOR4    mEmissive;   D3DXVECTOR4    mSpecular;   D3DXVECTOR4    mBumpScale;   D3DXVECTOR4    mSpecScale;   D3DXVECTOR4    mDiffuse;D3DXVECTOR4    mWeights; // used for TBN smoothing   D3DXVECTOR4    mTexScale;   uint32    mLayerCount;mutable uint32mUses;   struct Layer   {    mutable LPDIRECT3DTEXTURE9mpDiffuse_Alpha;    mutable LPDIRECT3DTEXTURE9mpNormal_Gloss;  std::wstring mDiffuseName;  std::wstring mNormalName;   };   Layer mLayers[ MAX_LAYER_COUNT ];};I'm not really using the layers anymore.  Instead of multiple pass materials, I have a single material on each object or world triangle, but support an arbitrary number of small or large decals on the world triangles for effects like blood, mud, vines, cracks, etc.My engine does proper shadowing & lighting, so you can't really have custom shaders for different materials for the most part.  I do use a 'glass' shader if a material's opacity < 1.0f.  Of course, glass doesn't really do the whole shadow thing properly, so it's not an issue.  I suppose you could have a custom shader to determine the diffuse & specular color, given a diffuse color, a normal, and the H and L vectors, but there's only so many ways to do that...;  What do you do when you render? How do you let the renderer know about the Material?I suppose the easiest would be:void Object::render(){video_driver->setMaterial( object_material );video_driver->renderGeometry( vertices );}And then the renderer just sets the light data and any diffuse map data, or bump mapping, or whatever. Is that right?Something simple along those lines?   ;  This depends on the responsibilities.My material implementation is used in the 3D editor as well.Therefore the material is responsible to provide all the information that is required to render a specified effect1.Material uses resource requirements from effect to know what data to load/generate2. At loadtime I associate each effect with and efx-object(the implementation in the dll) and requests which data to send at runtime3. At runtime the effect requests the resource references ( vertex pointer ,....) from the material and the assigned geometry and passes those to the efx-object.material: provides data information(texture ids ..)geometry: stores per vertex information(vertex data, uv coordinates, vertex attributes...)effect: requests required informationpasses the information the to right efx-objectefx-object: uses the data and does some fancy workThis interface is pretty generalized and thus allows pretty much every effect no matter if it is a pre or post effect or is run at runtime   ;  The Frame object pulls data from the material as needed.For instance the DeferredFrame object does most of the rendering, and composites the diffuse & normal maps together, and performs the lighting, so it grabs info from the material object as well as the lighting info, and the geometry chunks or entities being rendererd.The SelfFrame object ( for self-shadowing, although I don't really do this ) doesn't bother with the diffuse or normal maps, it's just using the geometry to render the shadow term to dest alpha.In the sense of Model View Controller, the material is not a View, but a Model. The Frame object is a View.;  I used something similar with combining graphics and physics material properties, but kept them seperate (more modular).  My engine is divided into several components, including graphics, physics, and simulation.  Each of these contains its own namespace to keep things sane.  Graphics=gfx, Physics=psx, Simulation=sim.  I then have a gfx::cMaterial class, a psx::cMaterial class, and a sim::cMaterial class.  The simulation engine basically provides a way for the game using the engine to handle game objects on a higher level, without worrying about graphics and physics and AI, etc.  So the gfx::cMaterial class contains data that the graphics engine will use (textures, dif/spec/amb/emi/shine, etc.) and the psx::cMaterial class contains data that the physics engine will use (drag, friction, mass, density, etc.).  Finally, the sim::cMaterial class provides higher level interaction, for example setting what happens if the material is shot or collided with (a shimmer effect for dragon scales would be an example).  This keeps things modular.  If I change out my graphics engine, it doesn't affect the other components.  Likewise the physics engine.- Enosch   