Effects / Materials - Management

Started by
3 comments, last by xynapse 12 years, 10 months ago
Guys,

before i decide how to manage properly the materials / post processing effect i would like to ask you for any directions, not to make a mistake and pick the most straight-forward technique to do it.

The engine i'm currently developing is almost ready, there are two things missing:




1) Effects management - what I'm thinking about here is to have an ability to manage the effects affecting the final render, let's say i have a script and in the init phase i code:



void main()
{


//load levels, setup cameras etc...

//Effects:

Postprocessing.addEffect("Effect_blackandwhite");

Postprocessing.addEffect("Effect_bloom");

}






Then later on when an event happens, i can manage and take off some effects and put new ones:




if(Game.sceneTime()>120)
{

Postprocessing.removeEffect("Effect_blackandwhite");

Postprocessing.addEffect("Effect_normalcolors");
}








I have all the shaders completed, and here's what i think should be done to achieve this ( correct me please if i'm wrong ):

- Build a vector "v_Effects" with a list of pointers to compiled postpro effect shaders.

- Build a vector "v_ActiveEffects" with a list of pointers to shaders added via Postprocessing.addEffect method




When in render, i






//iterathe through v_ActiveEffects,

for(...)
{
bind v_Effects[v_ActiveEffects[iterator]->shader]->shader

bind effect FBO and render to texture,

unbind v_Effects[v_ActiveEffects[iterator]->shader]->shader

}







Now i believe each effect iteration / render should get a texture input from the previous effect texture, am i correct?

The final stage is to copy the texture from the latest effect into a main Frame texture object.

All effects are compiled / linked when application starts, so the only thing to happen next when rendering is to bind a specific shader.


Any better ideas guys, good solutions?








2. Materials manager - this is connected strictly with the rendering process and materials are initialized when models are loaded.




I can't think of a way how to do it, if i could ask you guys to propose some idea - please?

- how do you store the materials ?

- how do you pass them to the shader (struct?)







Thanks for any comment on this!







perfection.is.the.key
Advertisement
Ok, never mind the 1st point, already implemented.




Well i hope somebody can say something in regards to Point 2 at least..?

I came up to an idea,

let's say a model is loaded and a texture is to be created.

I load a file called texturename.material which has :



ambient x,y,z

diffuse x,y,z

specular x,y,z

srcblend


dstblend




within.

This is stored within model so now when a call to render is called it passes a small structure to fragment shader telling what are the ambient/diffuse/specular values.

If src/dst blend is available, enable/disable the corresponding states in GL.


Correct or i am missing something here?
perfection.is.the.key
Okay I will have a go (Btw I think this has been discussed before in the Graphics Programming and Theory Forum, as it is not really OpenGL specific).
Each renderable object should have an associated material. The material should specify the shader it uses, and parameters that should be used with that shader. My system uses a simple effects frame work I wrote myself that also allows state changes to be data-driven, and shader parameters to be aliased as "effect parameters", so that I can set multiple shader parameters with a single effect parameter, or give effect parameters special names that cause them to take specific values from my engine automatically (e.g. "MODELVIEWMAT" would automatically take the model view matrix as a value when the material is bound).
So when you render an object, first you look at its material, and bind its shader, undate the shader parameters with the material parameters, and set general state. Then you can render the object.


FYI my effect files looks like so:


<effect name = "example">
<state_block>
<state name = "DepthTest" value = "true"/>
<state name = "CullBackface" value = "true"/>
</state_block>
<vertex_shader file = "\Shaders\example_vs.glsl">
<parameter name = "MODELVIEWPROJMATRIX" parameter = "uModelViewProjMat"/>
<parameter name = "SomeOtherParam" parameter = "uSomeOtherParam"/>
</vertex_shader>
<fragment_shader file = "\Shaders\example_fs.glsl">
<parameter name = "ColourTexture" parameter = "uColourTexture"/>
</fragment_shader>
<shadow_state>
<state name = "DepthTest" value = "true"/>
<state name = "CullBackface" value = "false"/>
</shadow_state>
<shadow_fragment_shader file = "\Shaders\example_sfs.glsl">
</shadow_fragment_shader>
</effect>


You can see I have extra parts in there for when I am rendering shadow depth buffers, so that I can write depth only, and not waste time doing colour and lighting calculations or writes.
It occurred to me this only solves a bit of your problem. As my models and materials are all procedurally generated at the moment, setting the values in a data driven manner slipped my mind.
For a particular model you could also have a file that specifies values for the parameters, e.g.:

<material name = "test mat 1">
<param name = "ColourTexture" value = "\Textures\test.png"/>
.. etc ..
</material>


In code you would want your Material class to have a function like
void set_parameter(string name, type value).
If you are using C++ then I can recommend using a boost variant type for the value, as it saves you having to have type specific code every where. If you are using some other weakly typed language then you will have an easier time of it. Use some sort of visitor pattern to actually set the parameters in a shader using the right glUniform function.
General state setting can be encapsulated quite easily by wrapping the different GL state setting functions in a class that will also parse and store the parameters from a string, and have a static factory function, then you can add the function to a map, mapped by the state name. e.g.


struct glStateSetter
{
virtual void parse_val(string val);
virtual void set();
virtual void unset();
}

struct glBlendFuncState : public glStateSetter
{
virtual void parse_val(string val)
{
// parse the two glBlendFunc parameters _a and _b from the val string into GLenums here.
}
virtual void set()
{
glBlendFunc(_a, _b);
}
virtual void unset()
{
glBlendFunc(default, default);
}

static glStateSetter* create_instance() { return new glBlendFuncState(); }

private:
GLenum _a, _b;
}

std::map<string, glStateSetter*(*)()> stateSetterMap;
stateSetterMap["glBlendFunc"] = glBlendFuncState::create_instance;



If you interested in my material and effect system shoot me a PM.
Oh sorry for posting this in GL specific thread, right my mistake.




Thanks bluntman, that's all i really needed to know.




Cheers mate.
















perfection.is.the.key
bluntman, great stuff, that's clear but i would like to have a closer look on your implementation as it looks very well prepared ( PM sent :) )











My effects manager is a class that takes care of the whole 'post processing' stuff and it is finally complete.
The name can be confusing, but it's working v.well. Effects can be managed within scripts, and the only thing left now is Materials management.
The approach i was thinking about is to have a global engine MaterialsManager class holding a list of loaded materials within.


When an object is to be loaded - it calls materialsmanager to load/parse a material file and stores a pointer to struct held in materialsmanager list.

Now when render kicks in, model calls:





Game->MaterialsManager()->BindMaterial(m_Model->material);

...


...

Game->MaterialsManager()->Unbind();

// m_Model->material - pointer to a materialsmanager list entry














EffectsManager in action.

67150a22.jpg




02d18bc7.jpg




8cde9875.jpg
perfection.is.the.key

This topic is closed to new replies.

Advertisement