_______________________________________________
osg-users mailing list
osg-...@lists.openscenegraph.org
http://lists.openscenegraph.org/listinfo.cgi/osg-users-openscenegraph.org
I also implement a shader composition framework for a client, based on osg shader composition, so remove it will be a big loss.My implementation handle OpenGL version, some pragma (optimize and debug), generate a main function for vertex and fragment shader based on what is found in shaderComponent list. So change from previous shader composition to new one will not be straight forward.
some thought about new shader composition
1)
OpenGL Shading Language specification
3.3 Preprocessor :
#pragma allows implementation dependent compiler controlso pragma "requires" and "import_defines" should be use by shader compiler, replace them by "osg_requires" and "osg_import_defines" could be prevent futur pragma collisions. Thought ?
Define a main function with all possibility and use define to choose the ones to enable and the ones to not will makea really complex shader, imagine, you optionally use- instancing
- bump/deplacement mapping
- vertex blending
- material/texture/multi-texture- lighting/shadow- fog- physic- one/multi fragment outputYou will be quickly crazy. The one that work with SpeedTree Shader knows what I am talking about.
This is why I prefer your previous approach that inject code found in StateAttribute in final program.It is also less intrusive. If i need to insert a new shader component in the program, no need to change mainshader.
More over, I introduce some new ShaderAttribute like "camera" to define where fragment shader output have to go,or "drawable" to define which vertex shader input are available, "Instance" to optionally use draw instance, ... so don't remove ShaderAttribute. With modern OpenGL and depreciated data like fog, light, ... we need a way to introduce our custom attribute.
I create a nodekit osgLighting just to manage different light source. I have 5 different light source (sun, car, streetlight, ...) that all use shaderAttribute to define data that compose the light and shader that use this data. So don't remove shaderAttribute this is really a good idea you have here !!!
3)
On a performance point of view, it will be a good thing to use subroutine to enable/disable feature.Many different path in shader composition result in many different program. And so many changeof program in one frame, perhaps use the program A, then the program B, then the program A again...This is the main problem I currently have in my shader composition implementation.
4)I always think that lack of define injection in shader is a drawback in osg. With your function and name convention,this will be difficult to add this feature. Replace import_define by import_module will fix this.
Because we talk about shader module, lighting, fog, bump mapping, shadow ... all of this could be define as shader module.
Hi David,On 14 February 2015 at 14:24, David Callu <led...@gmail.com> wrote:I also implement a shader composition framework for a client, based on osg shader composition, so remove it will be a big loss.My implementation handle OpenGL version, some pragma (optimize and debug), generate a main function for vertex and fragment shader based on what is found in shaderComponent list. So change from previous shader composition to new one will not be straight forward.Is there a chance you could create an example that illustrates how you are using the old osg::ShaderComposition framework?
some thought about new shader composition
1)
OpenGL Shading Language specification
3.3 Preprocessor :
#pragma allows implementation dependent compiler controlso pragma "requires" and "import_defines" should be use by shader compiler, replace them by "osg_requires" and "osg_import_defines" could be prevent futur pragma collisions. Thought ?Right now I would prefer to avoid adding the osg_ prefix as it's a bit clumsy, and the approach needed be OSG specific.I am consider other additions as well - such as having shaders be able to request the linking of other shaders - so the app could link a single main shader that pulls in the rest of the shaders to be linked to the program. Another possible addition would be to have osg::Program settings controllable via #pragmas. Right now I want to keep things simple though.
2)Define a main function with all possibility and use define to choose the ones to enable and the ones to not will makea really complex shader, imagine, you optionally use- instancing
- bump/deplacement mapping
- vertex blending
- material/texture/multi-texture- lighting/shadow- fog- physic- one/multi fragment outputYou will be quickly crazy. The one that work with SpeedTree Shader knows what I am talking about.The new shader composition framework doesn't add complexity where none exists. If there are many different combinations that need to be supported then this complexity will be reflected in the shaders, but at least the developer will be able to see it directly and account for the possibility of different combinations.
I create a nodekit osgLighting just to manage different light source. I have 5 different light source (sun, car, streetlight, ...) that all use shaderAttribute to define data that compose the light and shader that use this data. So don't remove shaderAttribute this is really a good idea you have here !!!Have you published your osgLighting so that others can review it?
I do this for the same client than ShaderComposition so osgLighting is also close source.
4)I always think that lack of define injection in shader is a drawback in osg. With your function and name convention,this will be difficult to add this feature. Replace import_define by import_module will fix this.
Because we talk about shader module, lighting, fog, bump mapping, shadow ... all of this could be define as shader module.As I explained above code injection is possible right now. It's not possible to know what you mean by import_module, it's such an open ended thing. import_define currently has a very specific GLSL based implementation, it literly is all about provide #define implementations for the GLSL compiler to utilize.
I don't see where you see problems. The old ShaderComposition is still there, and basically nothing has changed, as the new feature is orthogonal to the old one.
I'm using some adapted version of the ShaderComposition framework, and it still works with the current trunk, so could you please provide some example what is failing?
I haven't had a chance to really dive into the implementation details, so forgive me if my concerns are completely overblown. Like David, I can't really provide a concise example program that demonstrates how I'm currently using the ShaderComposer framework. However, there are a couple features of the existing framework I'd like to point out that are absolutely critical for my use case.1) Being able to override osg::ShaderComposer::getOrCreateProgram(). This is huge, because I can implement my own algorithm for composing shader code. It also gives me control of how the osg::Program object is generated and allows me to automatically apply uniforms based on the shader components. Another benefit is that I can implement my own shader caching strategy.
2) The osg::ShaderComposer object is called within the context of osg::State::apply. This is crucial, because it allows my composer to automatically apply textures based on the specified shader components. For example, if I wanted to add caustic lighting to the scene, my custom shader component would specify the caustic texture and shader code. The composer would then apply the texture to the next available texture unit and automatically apply the necessary sampler uniform. This makes it easy for us to define self contained shader effects that use textures, without needing to be aware of the scene and which texture units are available. This is also used for adding texture projected lights, ambient light cube maps, ramp-based lighting models, etc...
If the new framework allows for such use cases, then great! If not, then I think it's reasonable to keep the old framework around for advanced use cases that require more low-level hooks into the scene graph.
Again, the new framework looks great and I'm not criticizing it at all. I'm just worried about losing years of work I've invested into the old framework.
I've just refactored my previous ShaderComposition driven attempt to use the new pragmatic scheme. (It turned out to be relatively easy)
At first glance the basics work fine, but I have some questions:
1. When will the debug output in console be removed? ;-)
2. I have some StateSet on top of a group representing my scene. Later during rendering a new element is added, but with some additional define.
My naive expectation would be, that the new element will be using the top-level program, recompiled with the new define.
Is this supposed to be working? What I want is to anonymously add some define for my subgraph, not caring which top-state it has been placed below.
Or do I somehow need to dirty something here to get a new Program (based on the code of the program on top + my new define) built for this sub-graph?
It seems to act differently :-(.
The difference my case is the fact, that the element is added at some point in time. I expect this is after all previous used combinations have been built.
Any idea where I could set a breakpoint to see if a new combination is created when I add the new define?
I've encountered some small problem in the shader composition example.
You are using GL_LIGHTING which per defintion is not allowed for macros.
Some glsl compilers will ignore this, but on my Quadro card it produces an error:
0(1) : error C0118: macros prefixed with 'GL_' are reserved
Hi Sebastian,
On 17 February 2015 at 16:33, Sebastian Messerschmidt <sebastian.m...@gmx.de> wrote:
It seems to act differently :-(.
It could be you've hit upon and bug, or perhaps just a mis-understanding of how things are meant to behave. I'd suspect the first possibility given how new the functionality is.
Any chance you could reproduce the problem by modifying the osgshadercomposition example in svn/trunk?
The difference my case is the fact, that the element is added at some point in time. I expect this is after all previous used combinations have been built.
Any idea where I could set a breakpoint to see if a new combination is created when I add the new define?
The work for tracking defines happens in osg::State::pushDefineList/popDefineList and selecting program and shader objects happen in Program header & .cpp and Shader header & .cpp respectively.
In osg::State you'll find the following methods that can be called to check the current state of defines, you'd need to call this between the push/pop of the DefineList.
std::string getDefineString(const osg::ShaderDefines& shaderDefines);
bool supportsShaderRequirements(const osg::ShaderDefines& shaderRequirements);
bool supportsShaderRequirement(const std::string& shaderRequirement);
Robert.
Indeed i did :-)
The problem is within the StateSet::merge function. The case in which i had the problem used StateSet::merge instead of directly setting the state.
Reinjecting the defines after merging solves the problem and after looking into the merge code, I suspect the error here.
Cheers,
Robert
In my opinion the biggest problem that shader composition (SC) needs to address is the code maintenance nightmare of having to copy, paste, or edit other peoples' shaders in order to add your own functionality.
So I am eager to understand how you will address that. How can I add a new shader component without editing the main() functions to support it? For example, take the shaders in the terrain displacement code. I want to add some gamma correction code into the fragment stage. Will I be able to do that without editing your shaders too?
I'll update and test against my code.Don't hold your breath, though ;-)
Anyways, thank you very much for this feature.
If we manage to solve the other problems with this release (serialization and VPB) it might evolve towards a really great major one.
Advocating for those, not wanting the old fashioned shader composition dying: I suspect I will run into problems as soon as I test the core-profile based stuff. In the old approach I do the BindFragLocation stuff based on the shader code parsed, which I cannot do anymore.But maybe there are ways around this.
One idea popping into my head was to provide some "createProgram" callback inside the stateset to gain control over those aspects. This might remove the need for a ShaderComposer etc.
Attached some example using merge (and changes avoiding GL_*).
Hi,
Hi Robert,I second this, as I've just stumbled upon the same use case. Maybe there is some other way around this, but I too need some control over the finally created program.
I was amazed by the simplicity of the new pragmatic shader composition - but yet it is so powerful. Well done! So, I was making good progress porting old shader composition code to pragmatic one until I hit the wall. The problem is, I don't see any obvious way to extend the current pragmatic shader composition API. If I may, I would suggest two things for consideration:
1. Add a new layer of abstraction for StateSet's define API, lets say class object ShaderDefine that we can subclass. The ShaderDefine (or any other suitable name) would contain std:string _defineName, std::string _defineValue and at least a less operator, since you are inserting definition into map, and virtual void apply(State&) const {}. Of course, the apply would then be called from State::applyDefineList() giving the user an opportunity for define's customization. So the new StateSet::setDefine() would look something like this: setDefine(ShaderDefine*, StateAttribute::OverrideValue);. Also, with the proposed abstraction it would be easier to write serialization support.
2. The greatest strength of old shader composer is ShaderComposer::getOrCreateProgram(). As others have already mentioned, this is the point where we used to gain control over the program composition. I'm personally using this control point for things like program->addBindAttribLocation/addBindFragDataLocation/addBindUniformBlock and for some other sanity checks. It would be great if we can somehow install a callback or overload some member to regain the control of the program composition.
Robert Milharcic
_______________________________________________
osg-users mailing list
osg-users@lists.openscenegraph.org
http://lists.openscenegraph.org/listinfo.cgi/osg-users-openscenegraph.org
_______________________________________________
osg-users mailing list
osg-users@lists.openscenegraph.org
http://lists.openscenegraph.org/listinfo.cgi/osg-users-openscenegraph.org
1. Add a new layer of abstraction for StateSet's define API, lets say class object ShaderDefine that we can subclass. The ShaderDefine (or any other suitable name) would contain std:string _defineName, std::string _defineValue and at least a less operator, since you are inserting definition into map, and virtual void apply(State&) const {}. Of course, the apply would then be called from State::applyDefineList() giving the user an opportunity for define's customization. So the new StateSet::setDefine() would look something like this: setDefine(ShaderDefine*, StateAttribute::OverrideValue);. Also, with the proposed abstraction it would be easier to write serialization support.
2. The greatest strength of old shader composer is ShaderComposer::getOrCreateProgram(). As others have already mentioned, this is the point where we used to gain control over the program composition. I'm personally using this control point for things like program->addBindAttribLocation/addBindFragDataLocation/addBindUniformBlock and for some other sanity checks. It would be great if we can somehow install a callback or overload some member to regain the control of the program composition.
I am not actively working with any code which would require shader composition at the moment but I saw few such efforts in various projects in the past, so I am really glad OSG is going to implement own scheme and users will not need to invent the wheel anymore ;-). As someone only mildly interested in the topic at the moment I only briefly looked at new shadow composition example, and have only one question.I noticed that we may add/override parts of shader code using setDefine( "USER_FUNC(args)" ) as in your example:stateset->setDefine("VERTEX_FUNC(v)" , "vec4(v.x, v.y, v.z * sin(osg_SimulationTime), v.w)");But I feel that this solution may be inadequate for large blocks of shader code which used would want linked instead of being effectively merged with parent "Ubershader" program.
Do you have a method or anticipate that such method can be added, which would allow to add or override whole shaders in effective Program applied to OpenGL context ? Something that ShaderAttribute was supposed to do in former ShaderComposition scheme ? For example whould this be possible to replace whole lighting.vert shader from your example with entirely different shader doing own lighting at some subnode and its StateSet ?
Well.. the possibilities really are endless. Today in osgEarth there are probably 15+ VirtualProgram modules for terrain alone, plus various others, and support for including custom user shaders (http://goo.gl/I51FHv).What they have in common is a contract: a set of legal injection points and function prototypes. None of these modules know about any of the others, and the built-in main() functions don't know about any of these modules beforehand. But as long as each one abides by the contract they will work together.Perhaps a contract-based approach can be built on top of the new #pragmatic system... that is what I am wresting with at the moment... Maybe using #pragmatic one could specify some pre-defined injection points. However it isn't clear then how you would inject multiple functions and multiple modules using the #define approach, or how you'd support overrides, etc.
One could keep together related stuff, like lighting uniforms for lighting define, textures and uniforms if it happens to be texture define... Then, at the apply, one could for example multiply uniform with state's model view matrix or use any other information that osg::State has to offer. For example:
class MaterialShaderDefine : public ShaderDefine
{
...
};
With old shader composer it is possible to do this by sub-classing ShaderAttribute. I also think that with ShaderDefine the define API would then be more consitent with other StateSet APIs:
stateset->addUniform(Uniform*, StateAttribute::OverrideValue)
stateset->setAttribute(StateAttribute*, StateAttribute::OverrideValue)
stateset->setDefine(ShaderDefine*, StateAttribute::OverrideValue)
BTW, I'm not suggesting here that ShaderDefine* should be internally keyed by pointer. Anyway, ShaderDefine is just an idea to be considered and nothing more.
Unfortunately, I don't have short example that can illustrate what isn't possible. I'm attaching a complex example that shows old shader composer in action. The sources are for SVN revision 13962. Also, OSG_EXPERIMENTAL must be enabled in cmake. The point of interest is probably examples/osgshadercomposerhelper/ShaderComposer.cpp.2. The greatest strength of old shader composer is
ShaderComposer::getOrCreateProgram(). As others have already mentioned,
this is the point where we used to gain control over the program
composition. I'm personally using this control point for things like
program->addBindAttribLocation/addBindFragDataLocation/addBindUniformBlock
and for some other sanity checks. It would be great if we can somehow
install a callback or overload some member to regain the control of the
program composition.
Perhaps osg::Program itself could be adapted to allow it to be easily
subclassed so that the shader selection, compilation and linking and
uniform/attribute setup could be managed by end users that wish to subclass
from osg::Program. Another approach would be to defer this work to a
helper object that gets assigned to osg::State. Perhaps the
PerContexProgram/PerContextShader classes could have a role here in some
way.
What I'd really need is a concrete example in front of me that illustrates
what functionality is needed but isn't possible. An example based on the
old osg::ShaderComposition would be fine.
First, I'm all for new #pragma(tic) approach, because I use uniforms for the same reason currently.Thanks for an easier way to do the same thing!Second, I'd like to clarify that I understand it correctly: #pragma is OSG specific and thus works with OpenGL2, right?