This week I worked on the shader system of the engine. The first thing I did was to translate the shader from the CG language, which is very similar to HLSL (the shading language used in Direct3D) to GLSL, the OpenGL shading language. The two are somewhat similar but there are some important differences. The most apparent one by looking at the code side by side is that in CG, the shader parameters – input, outputs and uniforms (variables constant throughout the execution on a set of shader inputs like the vertices of a mesh) – are specified in the signature for the main function, while in GLSL they are specified in the global scope.
The name of types and build-in functions is also different. An example of this are the floating-point vector types which in CG are called
floatn, where n is the number of components (eg.
float4), while in GLSL the equivalent would be
vecn. Also, some of the base types present in CG are not available in GLSL, like the
fixed real number types, thought these are only used for optimization reasons, so I replaced them with the
float type. Another important difference is in the conversion between types. In GC the following line is valid:
float3 offset = ((tex2D(refractMap, uv2) * 2) - 1) * alpha * color.w;
While in GLSL it must be written as:
vec3 offset = vec3(((texture(refractMap, uv2) * 2) - 1) * alpha * color.w);
(both texture functions return a 4-component vector, but in CG this gets comverted implicitly to a 3-component vector while in GLSL the operation must be explicit)
The last interesting difference in the shader types is in the way data is passed to the vertex shader and between shader stages. In GLSL 1.2 this is done by specifying the relevant data as an
out parameter. In the case of data being passed by the vertex shader to the fragment shader, this needs to be declared as an
out parameter in first and as an
in parameter in the second, in both with the same name and type. This last requirement is not present in CG, instead the out and in parameters are supplemented with an additional specifier:
//vertex shader void main(out float4 oPos : POSITION) // fragment shader void main(in float3 iPos : POSITION)
The next task I worked on was removing the two-shader system that was present in the engine, created by the fact that CG shaders can be activated independently of each other while for GLSL shaders this must be done on the combination of vertex and fragment. For now I’ve only implemented the code required for the highest setting because I had some doubts about the others.
For now, all the shaders necessary for the first scene compile but they produce broken output. Next week I’ll work on fixing them and implement the material classes needed for the high and medium graphics settings. After that I will probably get back to physics debugging where a problem with player-objects interaction makes the game hard to play.
As an update for the notebook problem I described in the previous blog post, this has now been fixed thanks to aquadran and the HPL1R project (https://github.com/zenmumbler/HPL1R). For those who didn’t read it, the problem was that some game items, including the notebook on the table at the start, which is necessary to go forward in the game, disappeared. The bug turned out to be in one of the mesh loading classes (
MeshLoaderCollada), that created broken geometry for some scaled objects.
Thanks for reading.
The part on conversions has been updated to remove unnecessary conversions that I initially thought were necessary.