MakingShaders
This is to explain in detail how to make shaders.
This is WIP until it's finished. This was all grabbed from Volshebnyi from the forum thread.
What is a shader?! A Shader is a small program, which affects every vertex and pixel of object. There are two parts of shader: vertex shader (this one can transform any surface, for example, it can make neck wavy) and pixel (fragment) shader (it can change color of every pixel on the screen). Vertex shader + pixel shader = shader program.
How to create shader
There are many shader languages. The only true is GLSL. It's C-like and easy to use language. You must compile shader before you can use it in program. Let's make a simple shader program. 1) Go to FoFiX\Data\Shaders\ and create two files: "myshader.ps" and "myshader.vs"
2) Open "myshader.vs" with notepad. Here's a code:
void main()
{
gl_Position = ftransform();
gl_Position.z = gl_Position.z - 0.01; //It's very-very important string!
}
It'll be our vertex shader. What is it doing? Nothing! =) It just transforms object like OpenGL standart program. Oh, it also moves object a little bit nearer.
3) Open "myshader.ps" with notepad. Here's a code:
void main()
{
gl_FragColor = vec4(1.0,0.0,1.0,0.5);
}
It our fragment shader. It makes all pixel of our object violet and half transparent. Cool? No! But let's try!
4) Shader program is ready for action! Let's use it in FoFiX. Where? CD songlist is the best option! Open src\Dialogs.py. Search "shaders." That's it:
if shaders.enable("cd"):
self.cassette.render("Mesh_001")
shaders.disable()
Delete these lines, we'll replace them with our new shader.
5) Still "Dialogs.py", line 1608. We need to enable our shader program.
shaders.enable("myshader")
That's it! Our shader is enabled! What about compilation? You don't need to compile, because shader module already compiled it and put it to shaders. 6) Let's draw a CDs and disable shader.
shaders.enable("myshader")
self.cassette.render("Mesh_001") #render CD
shaders.disable() # don't forget to disable shader!
7) shaders.enable() return False if shader activation failed, So we don't need to perform following actions if happened.
if shaders.enable("myshader"):
self.cassette.render("Mesh_001") #render CD
#You may place here other objects
shaders.disable() # don't forget to disable shader!
8) Done! Compile FoFiX. What shall we see in CD songlist? Violet CDs.
SST. Part II: Variables
1) Edit your vertex shader code:
uniform float time;
void main()
{
gl_Position = ftransform(); // don't forget about semicolons. It's not a Python!
gl_Position.z -= 0.01; //It's very-very important string!
}
We declared our first variable! Now we need to use it:
uniform float time;
void main()
{
gl_Position = ftransform();
gl_Position.z -= 0.01; //It's very-very important string!
gl_Position.x += sin(time); //CD dance
}
2) Good. Now we need to set this variable. "Dialogs.py", line 1608
if shaders.enable("myshader"):
shaders.setVar("time",self.time)
self.cassette.render("Mesh_001")
shaders.disable()
setVar function sets active shader's variable "name" value. If your shader is not active, you may do this:
shaders.setVar("time",self.time,program="myshader")
if shaders.enable("myshader"):
shaders.update()
self.cassette.render("Mesh_001")
shaders.disable()
shaders.update() updates all variables in shader. But previous code is much better:
if shaders.enable("myshader"):
shaders.setVar("time",self.time)
self.cassette.render("Mesh_001")
shaders.disable()
3) Done! Now about varying type. Vertex shader's Varying variables can be used by pixel shader. A small example. Edit myshader.vs:
uniform float time;
varying float alpha;
void main()
{
gl_Position = ftransform();
gl_Position.z -= 0.01; //It's very-very important string!
gl_Position.x += sin(time); //CD dance
alpha = abs(sin(time/10));
}
myshader.ps:
varying float alpha;
void main()
{
gl_FragColor = vec4(1.0,0.0,1.0,alpha);
}
4) Now CDs will blink.
Vectors, Colors
Vector types are like list type in python. There are 9 of them: vec2,vec3,vec4 (n-dimensional float vector), ivec2,ivec3,ivec4, (integer) bvec2, bvec3, bvec4, (boolean)
vec3 myvect; // don't forget!
myvect = vec3(1.0,2.0,3.0); // myvect = (1.0,2.0,3.0); - wrong!!!
myvect.x = 1.5; // myvect = vec3(1.5,2.0,3.0);
myvect.xz = myvect.zy; // myvect = vec3(3.0,2.0,2.0);
vec4 newvect = vec4(myvect.xy*2, 0.0, myvect.x); // vec4 newvect = vec4(6.0,4.0,0.0,3.0);
gl_Position = newvect; // only for vertex shader!
How to use your vector in shader. In shader program (myshader.vs):
uniform vec3 vect1;
uniform ivec4 vect2;
In python script:
shaders.setVar("vect1",(0.1,0.2,0.3),"myshader")
#if shader is enabled:
#shaders.setVar("vect1",(0.1,0.2,0.3))
shaders.setVar("vect2",(4,3,2,1),"myshader")
print shaders.getVar("vect1","myshader")
Color is vec4:
vec4 color = vec4(0.8,0.5,0.3,1.0); // red,green,blue,alpha
vec2 myvec = color.br; // vec2 myvec = (0.3,0.8);
color.a = (color.r+color.g+color.b)/3.0;
gl_FragColor = color; //only for fragment shader!
Uniform usage.
In shader program (myshader.vs):
uniform vec4 color;
In python script:
shaders.setVar("vect1",(1.0,1.0,0.0,1.0),"myshader") #yellow
Textures
Theory
Any shader program gets textures from the list of active textures. That's why your video card should support ARB multitexturing to use more than one texture. You can assign texture to shader using
glUniform1i(glGetUniformLocationARB("texture1",program),<ARB texture>)
<ARB texture> = 0 for glActive(GL_TEXTURE0_ARB) <ARB texture> = 1 for glActive(GL_TEXTURE1_ARB) and so on… You should reassign all textures each time shader is activated.
Types of textures: sampler1D, sampler2D, sampler3D, samplerCubeMap. Example:
uniform sampler3D Noise3D;
Shader module advantages
You can assign any texture only one time with that string
shaders.setTexture("texture_name", texture, "program_name")
And it will be assigned to a module each time you enable it. Parameters:
"texure_name" - name of your uniform; texture - raw texture "program_name" - name of program, that has that uniform. If this program is active, you may skip this param.
Example:
shaders.setTexture("Noise3D", noise.texture, "stage")
You may change assigned texture any time you like, just use setTexture function again:
shaders.setTexture("Noise3D", outline.texture, "stage")
Don't forget to use shaders.update() if you cahnge textures in active program to use new texture immediately.
Shader Development Environment
You can use a GLSL IDE to create your shader files and preview the effects.
* Lumina, a free crossplatform development environment for GLSL shaders.
* RenderMonkey, rich shader development environment (you can import shaders from it).