Dynamic Shader Class for Game Engine

Started by
11 comments, last by Ncyphe 13 years, 8 months ago
OK, I'm in need of some help guys.

I'm currently enrolled in a Game Engine Development class in which we, the class, sits down and we build a game engine that we will use for our senior project.

I am currently apart of the graphics team entrusted with the job of building a dynamic shader class.


What the class is supposed to do is be able to load and process any .fx file that gets passed to it by the main program. What this means is that I can't simply build in an "find parameter, fill with data" functions as I won't know what those variables will ultimately be named.

I've figured I could use an enum to store type definitions like "WOLRD, PROJ, VIEW, FLOAT, INT, VECTOR,..."

at this point, my brain starts melting to goo. I want to make it so that information for the shader is stored into material structures that make it easy to simply setup the shader, but what is the best way to setup such a struct, since I don't know what data types or how many will be used. Should the structure be composed of unions with references to the variable the data is supposed to fill.


Basically, if that makes little sense, all I really need is a good point in the right direction.
Advertisement
Quote:WOLRD, PROJ, VIEW, FLOAT, INT, VECTOR
World/View/Proj don't belong in that group - they're all of type 'matrix'.

You could store your values in key/value groups. To solve the 'union' problem, I'd probably make one group per type, e.g.
std::map<std::string,bool>    m_Bools;std::map<std::string,Vector4> m_Vectors;std::map<std::string,Matrix4> m_Matrices;
Quote:Original post by Hodgman
Quote:WOLRD, PROJ, VIEW, FLOAT, INT, VECTOR
World/View/Proj don't belong in that group - they're all of type 'matrix'.

You could store your values in key/value groups. To solve the 'union' problem, I'd probably make one group per type, e.g.*** Source Snippet Removed ***


Well, the reason I was including a view, world, proj typedef was so that the shader class would know which parameter to place the essential camera info, because, in the end, it could be named anything.
I'm not sure I understand your requirements. Can you give an example of the interface and how it would be used.
If I understand correctly you want a class to aid with using shaders.

So a shader usually has a Begin () and an End () call, in between the two you render your geometry, and the shader does its magic on that geometry.

Shaders also have properties, I know their called uniforms in OpenGL, I never figured out what you called them in DirectX... At anyrate, you need an easy way to store what these properties should be set to. Because the same shader might be used on several objects but require a different property.

So my solution for shaders was to create several classes.

Shader Class - I worked in OpenGL so I had to wrap up OpenGL's c code, you might just use the built in DirectX effect class (Expecially if your using XNA, that thing's nice.) This just handled the Begin() and End () and passing properties to the effect.

Material Class - I call it a material I don't know what the rest of the world calls it, but the Material has a reference to a Shader object and a list of pairs. The pairs were the property names and values. So like you'd pair "DiffuseTexture" with "WoodGrain.png" or however you handle your textures. Or you'd pair "WorldViewProjection" with the WorldViewProjection matrix. This made it easy to configure what was passed to the shader. Give your Material class a Begin () and an End () where in begin it starts the shader, loops through your pairs, and passes them to the shader. And then you have a simple shader material system.

Since I'm never really clear about anything here's some psuedo code of what I mean.

class Shader{    Begin (); //XNA, DirectX, or OpenGL stuff    End (); //XNA, DirectX, or OpenGL stuff}class Material{    Shader *Effect; //Mind the pointer if your not working in C++    List<MaterialPair> Properties;    Begin ()    {        Effect.Begin ();        for each MaterialPair in Properties        {            MaterialPair.Apply (Effect);        }    }    End ()    {        Effect.End ();    }}//Subclass this, and override Apply) for each type of pair (float, texture, matrix, etc)class MaterialPair {    string Name;    virtual Apply (Shader *Effect);}


Thats how I would do it anyway.

Furthermore I found it easy to create a simple text file that would be parsed and load in your MaterialPairs, this way you don't have to hardcode all your effects :)

~Tocs
Quote:Original post by allingm
I'm not sure I understand your requirements. Can you give an example of the interface and how it would be used.


I'll do the best I can.

The shader class I'm working on is more of a controller than a class that has set properties. Primarily, it will be scripts outside of the main program that will decide what to load. Thereby, my shader class has to be dynamic.

It has a function SetShader(...) tha sets the current shader, and it will have a function SetParams(...some struct...) that gets passed a structure full of data that will ultimately get sorted into the active shaders data variables.

In essence, my shader class must have a means to understand how to sort the data passed to it.


I think I figured something out, by using a map when the shader gets built, defined by the Main portion of the Engine, that has a set of strings that are the variable name sin the shader, and a D3DXHANDLE defining the shader variable handle.
Quote:Original post by Tocs1001
If I understand correctly you want a class to aid with using shaders.

...

~Tocs


Pretty similar to what I'm looking for.


Also, I know most people probably read my threads and think, "what the hell is he describing?" I post these threads to help jump start my mid, help me think, per say. Even if anyone posting is not sure if they're helping, they usually are.



Anyway.

Yes, I have a couple resource files.

ShaderResource <== Contains the shader pointer as well as the data defining it
ShaderData (was refering to it as material) <== Would contain data like texturemaps, bumpmaps, ets to be set in the shader


As I said, my shader class is essentially blind. Like being paid to do wok before you even know what kind of work it is.


Anyway, I think I have it figured out . . . if not, I'll be back.
I see, so you want this general system that sets data read in from a file. So, for instance you might have an XML file with the shader variable names and what they will be set to. However, you say you need a dynamic system. Do you also need to be able to affect variables from code? I'll assume so.

If the above is exactly what you are doing I would think of something like this:

Read in the XML file and put the data into a struct that lists the associations and also the shader file(s) it will need. Then take that struct into your shader manager and have it return a handle/pointer to the data. You can make some sort of vector that contains all this information or you can use DirectX 9's built in functionality (ApplyParameterBlock, BeginParameterBlock, EndParameterBlock; http://msdn.microsoft.com/en-us/library/bb205788%28VS.85%29.aspx). I don't know what is done in 10 and 11 sorry.

Steps:
1) Load in XML file.
2) Get reference to shader listed in XML file.
3) Load data structure with shader data, type, and name (string) associations.
4) Pass structure into shader manager.
5) Load up data in to parameter block.
6) Return handle to data.
7) Set entity/game object with shader handle/pointer and data parameter block (which is a handle/pointer).

Using:
When running through your objects they simply do something like:
shader->Begin( parameter_data, 1 ); (1 is the size of the array)
//do stuff
shader->End();

For more dynamic data you are going to have to simply do it like Tocs1001 stated. You can have it so the game logic can do something like this:

entity->graphics_object->shader->Set("color", RED);

It will be slow, but as long as you don't do it thousands of times per frame it probably won't matter (even in that case it might not; as always you should profile).

I also have more ideas on a more dynamic system for object transformations (example: model to world matrix). You can find these here: http://www.gamedev.net/community/forums/topic.asp?topic_id=574940

Did that help any?
Feel free to shoot some more questions about anything.
I want to thank everyone here who posted something, you were all great help.


I've figured out how I will implement my shader class.


When a function CreateShader(..) is called, it will ultimately create the shader; however, after the shader is created, the main program will have to call SetParamDefines() passing in a structure consisting of vectors contain both strings for the names being searched, and the types of data that they are.

When it comes time to draw the shader, I'll either use the technique Hodgeman suggested. Create a structure containing several vectors or pairs containing the string reference and the data. I'm not too thrilled about that idea because I would need to create a vector for ints, floats, D3DXVECTORs, images, bools, etc. It would seem rather clunky.

I'll be taking this to my professor tonight at my class's out-of-class meet . . . where the professor will just happen to be.
I just wanted to say one last thing. Going to see your professor is an excellent idea. In college, your greatest resource is your professors and your fellow students. Use them. They are much more valuable than even the internet in my opinion.

This topic is closed to new replies.

Advertisement