5
\$\begingroup\$

I'm trying to make a clean and advanced Material class for the rendering of my game, here is my architecture:

class Material
{
    void sendToShader()
    {
        program->sendUniform( nameInShader, valueInMaterialOrOther );
    }

private:

    Blend       blendmode;      ///< Alpha, Add, Multiply, …
    Color       ambient;
    Color       diffuse;
    Color       specular;
    DrawingMode drawingMode;    // Line Triangles, …
    Program*    program;
    std::map<string, TexturePacket> textures;   // List of textures with TexturePacket = { Texture*, vec2 offset, vec2 scale}
};
  • How can I handle the link between the Shader and the Material? (sendToShader method)
  • If the user want to send additionals informations to the shader (like time elapsed), how can I allow that? (User can't edit Material class)

Thanks!

\$\endgroup\$
  • \$\begingroup\$ I'm not sure that's such a good idea design wise. Are we talking about some generic material class, e.g. you define properties (like the ones listed above) and you'll essentially get one shader per material? Or would you just like "apply" it to one fixed shader program? I'd just stick to one fixed program per material, so you could just create the shader program just in time, compile and link it (then cache it). \$\endgroup\$ – Mario Oct 16 '13 at 10:04
7
\$\begingroup\$

It's a good idea to separate parameters into a few categories based on how often they're changed, or which other parts of the renderer they hook up to. For instance:

  • Frame parameters - like the camera matrix, screen size, and current time
  • Material parameters - like textures, specular and gloss values, etc.
  • Object parameters - like an object's world matrix, skinning matrices, etc.

If you're using uniform buffer objects it's convenient to make each category its own UBO as well; that way you can re-use UBOs, e.g. use the same frame parameters UBO across all shaders in the scene.

You can then write a little class to handle each group - for instance, have a FrameParams class that would handle setting all those parameters for a shader program. It would look up uniform locations at initialization, then later set all the uniforms appropriately, or update the UBO and bind it, each frame. You'd have one instance of this class for each shader program, probably as a member in your Program class.

If there are a few fixed sets of parameters used by different materials, you could write similar MaterialParams classes for each variation. For instance, one class could handle diffuse and specular colors while another could handle textures. If you need more variation than that, you're looking at a dynamic, data-driven parameter set - which is going to be more complicated, but still doable.

Each shader program could have a set of these parameter objects, kind of like a component-based system. When you want to set the parameters for a particular material, you find the appropriate parameters object in the program and call a method on it, passing in the parameter values for that material.

| improve this answer | |
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.