What do you want in a shader generator/editor?

i guess so.
Keep it up :slight_smile:

Some recent issues regarding conditionals, and efficient use of ā€œdiscardā€ have prompted some design rethinking. Also, after some real use in one of my projects, Iā€™ve decided the workflow is poor, and will be fixing that too.

Conclusion: Iā€™m doing some major design changes in the front end (the UI, loaders, libraries etc) to improve work flow, and shift to a more hierarchical and explicitly ordered structure. Iā€™m not totally abandoning the GUI editor, but the main focus is being shifted a more traditional text based language thats roughly the equivalent of the graphical editor, except with explicit ordering. Iā€™m also cleaning up/revising the node types system to hopefully make developing new node types much more straightforward.

Iā€™m very busy with other stuff at the moment, so this will continue to be a slow process.

Iā€™ve gotten the shader meta language to the point where Iā€™m happy with it. It is working very well, and can quickly generate a wide variety of shaders from one configuration. The shaders can depend on what shader inputs are provided, what tags are set in the scene graph, the what vertex data columns are present, and to a limited (but extendable) extent, what render attributes are present. It supports extensions to the set of factors that can effect shaders, as well as arbitrary custom code generator nodes, and easy use of custom shader code.

With a bit of work, I think I could implement a port of pandaā€™s autoshader in it now. All the features are there, and the workflow for implementing stuff is decent, but poorly documented currently.

There is a minimal example in the repo, but here is a more complex example. Iā€™m not providing the library file which contains some snippets of shader code to back some of the nodes used here. Hopefully Iā€™ll have a better example soon. This is from a closed source project, so I canā€™t really post everything needed to use it.

def fshader():
    # get vertex color
    vertexColor=Input("float4 l_color: COLOR")
    
    # multiply vertex color with color from diffTex if there is one
    diffTex=ConditionalInput("uniform sampler2D k_diffTex : TEXUNIT0")
    diffTexColor=sampleTex(diffTex)
    baseColor=Operator(False,"*",vertexColor,diffTexColor)
    
    # discard if we have an alpha tag and alpha is below threshold
    doDiscard=RequireTag("alpha")
    discardColor=ConditionalPassThrough(doDiscard,baseColor)
    alphaDiscard(discardColor)
    
    #apply decal texture if present
    decalTex=ConditionalInput("uniform sampler2D k_decalTex : TEXUNIT1")
    decalTexColor=sampleTex(decalTex)
    decaledColor=decal(baseColor,decalTexColor)
    finalColor=FirstAvailable(decaledColor,baseColor)
    
    # get color from material, or default if no material
    hasMat=HasMaterial()
    _rawMatColor=material()
    rawMatColor=ConditionalPassThrough(hasMat,_rawMatColor)
    defaultMatColor=Constant("float4","float4(0,0,0,0)")
    baseMatColor=FirstAvailable(rawMatColor,defaultMatColor)
    
    #get material buffer color, including matDecal if present
    matDecalTex=ConditionalInput("uniform sampler2D k_matDecalTex : TEXUNIT2")
    matDecalTexColor=sampleTex(matDecalTex)
    matDecaledColor=decal(baseMatColor,matDecalTexColor)
    matColor=FirstAvailable(matDecaledColor,baseMatColor)
    
    # get normal using normal map, or basic vertex normal if no normal map
    normTex=ConditionalInput("uniform sampler2D k_normalTex : TEXUNIT3")
    normFromTex=texNorms(normTex)
    normFromVert=Input("float3 l_normal : TEXCOORD1")
    norms=FirstAvailable(normFromTex,normFromVert)
    normColor=norm(norms)
    
    # output colors
    Output(finalColor,"float4 o_color: COLOR0")
    Output(normColor,"float4 o_normal: COLOR1")
    Output(matColor,"float4 o_misc: COLOR2")

def vshader():
    attrColor=Input("uniform float4 attr_color")
    vertColor=Input("float4 vtx_color : COLOR")
    matColor=MatColor()
    
    doVertColor=HasColumn("color")
    doAttrColor=HasColorAttrib()
    doMatColor=HasMaterial()
    
    vertexColor=ConditionalPassThrough(doVertColor,vertColor)
    materialColor=ConditionalPassThrough(doMatColor,matColor)
    atributeColor=ConditionalPassThrough(doAttrColor,attrColor)
    
    white=Constant("float4","float4(1,1,1,1)")
    vColor=Operator(False,"*",atributeColor,vertexColor,materialColor)
    finalColor=FirstAvailable(vColor,white)
    Output(finalColor,"float4 l_color: COLOR")
    
    modelvshader()

This is all very interesting, but Iā€™m not sure what you mean by this:

Do you just mean example code?

I simple mean the particular example in my post requires a lot of other stuff (models, textures, custom loaders, my deferred shading setup etc) which Iā€™m not releasing, so you canā€™t run that example. There are 2 functional examples you can run included in the repository, but they are somewhat less interesting.

Oh, thatā€™s fine. If you donā€™t mean a custom shader by deferred shading setup, though.

Hey Craig, Iā€™m replying here instead of the Feature Requests thread.
I donā€™t understand how to use your shader generator, Forgive me if theres a doc somewhere I missed.
I see these lines:

shaderManager=manager.getManager(["library"],"graph/lit.gen")
shaderManager.genShaders(render,"ShadersOut/debug")

From what I see shaderManager.genShaders() method takes a nodepath as the first argument, like nodepath.setShaderAuto(). Whatā€™s the second argument? The shader which was generated by the getManager() call?

Other than that do we need to write the Cg shaders which the shader generator will use ourselves? Because Cg is beyond me, maybe I should wait a bit more until someone makes a collection of shaders which can be used with your shader generator.

Anyway, keep up the good work :slight_smile:

It loads some content from a list of library folders (In this case just ā€œlibraryā€, look in there to see said content), then runs a script (In this case ā€œgraph/lit.genā€) that defines the shader builder. The second arg to genShaders is simply an optional path to dump debug files to so you can see what it generated.

The manager module (which I just added a few hours ago) provides a simplified API for this good for the case when you donā€™t want to make multiple different shader builders from different scripts using the same Library. In the Manager module, you will see the Manager class, its pretty simple really, it provides methods for getting shaders onto your nodePaths (genShaders) and making individual shaders (makeShader). Mostly the manager is there to hide the renderStateFactory from you so it wonā€™t confuse you (while its awesome, you really can ignore it unless you are adding custom node classes such as those in nodes.py)

To customize the shader generator to meet the needs of your project (say you wanted to add support for glow maps or something), you will need to edit the script file that defines the shader generator, and likley need some extra bits of CG code to splice in that you can provide by defining a new node in the library.

If you actually want to customize or extend the included scripts to create/edit new shader generator specifications, thats how you do it, but I recommend a very strong understanding of CG to try. With the current lack of good ways to debug issues, it can be a real challenge to figure out whats not working right. That said, if you just want to tweak some constant and equations (say swap in linear fog), such changes to the library and scripts are trivial.

I really need to draw out some sort of map of the project showing how all the different classes, files, and such relate. Its very strangely constructed (though not all that complicated).

Anyway, if you donā€™t want to dive into CG (I strongly recommend lots of CG coding, its great fun), you probably want to stay away from writing content for my shader generator. That said, if others provide the features you need, it should be very simple to use in your projects.

Ok, I guess I donā€™t hve the required knowledge to use it for my project yet.

Maybe Pydoc or Doxygen?

Iā€™d love to learn Cg, but itā€™s just too complicated. I donā€™t know how many attempts Iā€™ve made already. I even have a printed version of the Cg Tutorial.

Some major improvements to the shader generator (its getting close to done aside from content). Along with the improvements, I updated my shader tutorial to include example usage of my shader generator: github.com/Craig-Macomber/Shader-Tut

Its not great, but it includes some basic custom shaders in panda with explanations, and some trivial use of the shader generator (with rather lacking explanations). CG really is a very simple language (much simpler than C), and Iā€™d like to see more people comfortable using it. Hopefully this will help overcome some of the confusion about it.

Iā€™d like feedback on the intelligibility and usefulness.

Iā€™m really looking forward to this.

ā€¦but to be honest it still looks hard to use. If thereā€™s a artist friendy gui shader builder then there should be a way to save all thatā€™s done to a file and then in code just point to a node and say ā€˜use this shader from fileā€™ it should take care of inputs, off screen buffers and all the stuff the shader needs to work.

Just like setShaderAuto() it should worke like a DoTheMagicIDontCareHowInFactImTooStupidToKnowAnyway(nodepath, ā€˜my_shaderā€™) function.

Maybe itā€™s too much to ask for, but Iā€™ve got nothing to loste so Iā€™m still asking for it.

If you donā€™t want to write your own custom shader generator, its one line to load one, and one line to dump a node into it to have it generate shaders for every geom.

# load some predefined shader generator
shaderManager=shadergenerator.manager.getManager(["shadergenerator/library"],"shadergenerator/graph/basic.gen")
# use it on what ever nodes you want, just like the auto shader
shaderManager.genShaders(myNode)

Take a look at the usage tutorial: github.com/Craig-Macomber/Shade ā€¦ ain.py#L89

If you want to write your own custom shader generator (which is the only real part of the project that interests me.), of course its a bit more complex. Honestly, regardless of the GUI, letting artists optimize lighting equations is not going to work well (unless they can understand code, in which case editing code is fine, then they are also a coder). Script a new shader generator or use an existing shader generator, and feed it nodes on which the artist has setup the things the shader generator uses (tags, render attributes, shader inputs etc). What GUI you have for your artist to do this is a different issue.

I had some different plans initially, but they were not a good idea.

I updated the shader generator to have an option to output svg graphics of the graphs, some output from my game is dumped here: craig.p3dp.com/ShaderGraphs/

In the root direction there (linked), there are the generator graphs for two different shader generators (one for models, and one for lights). Those are generated from the script files. In the ā€œoutputGraphsā€ folder are graphs representing the "ActiveGraph"s (which directly translate to shader source) produced for different renderStates. Those are produced from the generator graphs using the renderStates.

All the graph processing and outputting code is in the shaderBuilder module ( github.com/Craig-Macomber/Panda ā€¦ Builder.py )

There is still lots more debugging info Iā€™d like to add to the graphs, but they are pretty informative as is. You can see that a wide variety of different shaders were generated from my model shader generator (it generated all the nodeā€¦ ones).

I think the next improvement would be to detect which ActiveNodes (those in the output graph) came from which generator nodes, and perhaps even include line numbers and/or script lines which resulted in those nodes in the ActiveGraph.