Ubershaders is not for putting vertex and fragment shaders in one. That's not possible at all with GL or D3D. They require different source for each.
Ubershaders are for combining different materials or effects in one. Like some objects maybe have specular texture, but some not, then you can do something like this:
| vec4 spec = vec4(0);
if (uHasSpecular)
{
vec4 = tex2D(specularSampler, uv);
}
|
Then you set uHasSpecular unfirom to true or false for specific objects (or shader programs). Theoretically driver should notice that this uniform doesn't change and compile only one variant (or two different ones for two boolean values).
If you want to just put vertex and fragment shader in same source *file*, then you can easily do that with preprocessor:
| .. // put here common part, like uniforms and varyings
#if defined(VERTEX_SHADER)
void main() {
gl_Position = ...;
}
#elif defined(FRAGMENT_SHADER)
void main() {
gl_Color = ...;
}
#endif
|
And then simply prepend "#define VERTEX_SHADER\n" string when compiling this source code for vertex shader object, and "#define FRAGMENT_SHADER\n" when compiling fragment shader. That's pretty much it.
With glShaderSource you can do this even without manually concatenating strings - it allows to pass multiple strings that are processed sequentially. So something like this will work just fine:
| const char* vertex_src[] = {
"#define VERTEX_SHADER\n",
combined_source_code,
};
const char* fragment_src[] = {
"#define FRAGMENT_SHADER\n",
combined_source_code, // same string as in previous vertex_src array
};
glShaderSource(vertex_object, ArrayCount(vertex_src), vertex_src, NULL);
glShaderSource(fragment_object, ArrayCount(fragment_src), fragment_src, NULL);
|