material system

Started by
12 comments, last by ekba89 11 years, 11 months ago
Hi, I'm trying to create a material system for my deferred renderer also I'm using effects framework with dx 11. Currently I don't have material class and I have a class for every shader that I'm using and I'm setting shader parameters from that class but obviously it is not a good approach and I was using it just for the beginning. So before go any further I want to change it. And I'm trying to find what my material and shader classes should include and how they use that information. For example material obviously should know about material related variables in shader but there are other variables that are not related to how things are seen like matrices so which part of the game should be responsible for setting these kind of variables. And I'm thinking about writing xml for every shader which includes details about variables in the corresponding shader so I can use one universal shader class which has list of shader variables created using the information in xml file.
Advertisement
For example material obviously should know about material related variables in shader but there are other variables that are not related to how things are seen like matrices so which part of the game should be responsible for setting these kind of variables.
Matrices are material parameters. There have been a few discussions in the past about that and the hint was about considering parameters as opaque blobs. I cannot quite point you to the exact thread, hopefully someone will search for it.

I'd elaborate a bit on that concept though. Some special values must obviously have a special binding. I think D3D somehow has this built in (I think it's called DXSAS but never looked at it). In general, I considered my parameters a sequence of opaque blobs with an header. If the header mandated the use of an environment value - such as MVP or light info - then the blob would count 0 bytes and I would pull out the value from runtime.

Who does the pulling? Someone very close to the renderer, but not quite like it. I've called my pullers uniform fetchers.

Previously "Krohm"

Just to give you some input, here's my Material class (stripped of its member functions):

class Material
{
public:

enum CullFace
{
DONT_CULL,

CULL_FRONT,
CULL_BACK
};

enum DepthTest
{
DONT_TEST,

DEPTH_TEST_NEVER,
DEPTH_TEST_ALWAYS,

DEPTH_TEST_EQUAL,
DEPTH_TEST_NOT_EQUAL,

DEPTH_TEST_LESS,
DEPTH_TEST_LESS_EQUAL,

DEPTH_TEST_GREATER,
DEPTH_TEST_GREATER_EQUAL
};

enum BlendMode
{
DONT_BLEND,

BLEND_MODULATE,
BLEND_ADDITIVE,
BLEND_TRANSPARENT
};

vec4 ambient;
vec4 diffuse;
vec4 specular;

bool colorWrite;
bool depthWrite;

CullFace cullFace;
DepthTest depthTest;
BlendMode blendMode;

protected:

// contains shader program id, etc.
shared_ptr<MaterialProxy> m_proxy;

// texture layers contain textures and texture coordinate
// generators used to scroll, stretch and rotate textures
vector<shared_ptr<TextureLayer>> m_textureLayers;
};


I use a uniform buffer object to update material colors etc. efficiently, I think there's a similar concept available in DX.
Wunderwerk Engine is an OpenGL-based, shader-driven, cross-platform game engine. It is targeted at aspiring game designers who have been kept from realizing their ideas due to lacking programming skills.

blog.wunderwerk-engine.com

There have been a few discussions in the past about that and the hint was about considering parameters as opaque blobs. I cannot quite point you to the exact thread, hopefully someone will search for it.


Here you go. This is most likely the more complete thread about material systems.
No, that was not quite the post I was referring to. It's related, seems to involve the management of the various materials but it does not seem to go much in depth about what a material is.
I think this could be slightly more in my line of thinking... but I'm not 100% sure. It seems to contain all the details.

As a side note: I would avoid the material structure above. It is adeguate for D3D7 and FFP: an extremely inflexible way to think at things now.

My best suggestion to OP is to approach this iteratively, by focusing on the needs of a particular product first. For a start, Vertex shader + pixel shader + (a subset of) ROP settings coupled with constant data will likely suffice.

Previously "Krohm"

First of all thanks for the advices. And here is my strategy. First I think I should change my shader variables.
Currently they are like below and I have proper ID3DX11Variable type for each them.

float3 lightDirection;
float3 lightColor;

And in order to use them as raw data with ID3DX11EffectConstantBuffer it should be like this

cbuffer LightInfo
{
float3 lightDirection;
float3 lightColor;
};

And shader class should have a list of ID3DX11EffectConstantBuffer and should know what they contain. And material class should have actual buffers for these variables. I'm not sure what is the best way to make shader class know about contents of buffers though. And another thing I'm curious about is that shader variables are filled by different parts of the game. I mean view and projection matrices come from camera class, some values come from object's class etc. And what is the best approach to update material contents?
That was my strategy and my problems biggrin.png. Is it a viable strategy or does it need to change?
In my engine I have a Frame Constant Buffer that is only updated once per frame and containts matrices like View, Proj, ViewProj matrices and other constants that only change once per frame... This CB is accessible to all shaders in the CB slot 0. Then I have a ActorCB that contains the constants of a actor, and the number of times it is updated = number of actors drawn, and the same goes for the other Constant Buffers

In my engine I have a Frame Constant Buffer that is only updated once per frame and containts matrices like View, Proj, ViewProj matrices and other constants that only change once per frame... This CB is accessible to all shaders in the CB slot 0. Then I have a ActorCB that contains the constants of a actor, and the number of times it is updated = number of actors drawn, and the same goes for the other Constant Buffers

Yes I was thinking about something like this but how do you know what is inside the buffers. I mean different shaders have different CBs. And some of them might not have per frame matrix data. Are you using another file that has information about CBs or is there a way to find out CB when compiling the shader.
I have a file called ShadersHeader.hlsl that looks something like this:

//Samplers
SamplerState gTriLinearSampler : register(s0);
SamplerState gTriPointSampler : register(s1);
SamplerState gAnisoSampler : register(s2);
//Constant Buffers
cbuffer cbImmutable : register(b0)
{
//Constants that never change during gameplay
}
cbuffer cbPerFrame : register(b1)
{
float4x4 gView;
float4x4 gProj;
float4x4 gViewProj;
float4x4 gInvViewProj;
float4 gEyePositionFarPlane;
}


Then I #include this header in every shader file that needs some/all of this constants. So when I update the constant buffer at slot 0/1 the constants will be available to every shader... you just have to make sure you don't override constant buffer slots.
I'm not sure how the effects framework will deal with this, but it will probably work the same way, anyway why don't you write your own effect framework? You will gain more control over the shaders and probably a performance boost.

EDIT: In Effects11 I think you can share samplers/constant buffers, and other resources, across techniques by using Effect Groups, although I'm not sure how they work...
Thanks for the reply. I'm not against writing my own effect framework but currently I don't need something like that and before I wrote a simple effect framework so I know how it works. And about my question, I don't have problems with CBs that are used by all shaders. My question is lets say there are two shaders A and B. And they have different variables in CBs. So to create corresponding variables in shader and material class I should know about what their CBs contain. And my solution to that is having xml file for every shader which contains info about shader variables. Something like this.

//SHADER A
cbuffer buffer
{
float4 a;
float3 b;
};

//xml
<variable name="a" type="float4" />
<variable name="b" type="float3" />



//SHADER B
cbuffer buffer
{
matrix a;
float b;
};

//xml
<variable name="a" type="matrix" />
<variable name="b" type="float" />


And this way I can know what it contains and its size. But I'm not sure this is the easiest and the most efficient way to do this.

This topic is closed to new replies.

Advertisement