Skip to main content
gamedev.net
🔒 Locked

Engine material systems

Started by Endar Jun 2, 2006 at 2:43 AM 9 replies 10.4k views
Original Post
Endar
Endar
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?
[size="2"][size=2]Mort, Duke of Sto Helit: NON TIMETIS MESSOR -- Don't Fear The Reaper
SimmerD
SimmerD
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.
Endar
Endar
Quote:
Original post by SimmerD
I 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?
[size="2"][size=2]Mort, Duke of Sto Helit: NON TIMETIS MESSOR -- Don't Fear The Reaper
Basiror
Basiror
I have a rather complex material system

Ttextures 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 fog
so you specify the layers and the effects as you see underneath

Effects 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 use

Efx-objects describe certain effect possibilities
e.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 easily

texture:
-texture data

material:
- layer0: "sometexture"
- layer1: "sometexture2"
- layern: "sometexturen"
- efx1 //graphic effect e.g.: n-layered terrain
- efx2 //bullethit
- efx3 //fog ....

effect
- id: efx1
- use: nlayer_blend


efx-object
- type: graphics
- dll: xyz.dll
- can: nlayer_blend,4layer_blend .....
- priority: 100
http://www.8ung.at/basiror/theironcross.html
Endar
Endar
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.
[size="2"][size=2]Mort, Duke of Sto Helit: NON TIMETIS MESSOR -- Don't Fear The Reaper
SimmerD
SimmerD
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;            bool     shadow_cast    = true;            bool     shadow_receive = true;            bool     light_receive  = true;            bool     blocks_light   = true;            bool     walkable       = false;                        bool     deadly         = 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;	ID          mID;        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 uint32		mUses;        struct Layer        {	    mutable LPDIRECT3DTEXTURE9	mpDiffuse_Alpha;	    mutable LPDIRECT3DTEXTURE9	mpNormal_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...
Endar
Endar
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?
[size="2"][size=2]Mort, Duke of Sto Helit: NON TIMETIS MESSOR -- Don't Fear The Reaper
Basiror
Basiror
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 effect


1.
Material uses resource requirements from effect to know what data to load/generate

2. At loadtime I associate each effect with and efx-object(the implementation in the dll) and requests which data to send at runtime

3. 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 information
passes the information the to right efx-object


efx-object: uses the data and does some fancy work


This 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
http://www.8ung.at/basiror/theironcross.html
SimmerD
SimmerD
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.
Enosch
Enosch
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
python_regious
python_regious
For completeness and reference:

Basiror's original thread on this topic.

You should also read the thread linked to by that thread, as it is also very useful.

Whether you want something so complete and extensive is another matter however, and various other implementations (for instance using scripting systems) are mentioned in those two threads.
If at first you don't succeed, redefine success.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.