I’ve been testing Tom's new GLSL demo under ATI 9700 Pro with Catalyst 3.10 and there are a few things to note to make it work:
a) First, Tom uses “casting” instead of construction to create variables, but GLSL only allows construction there is no typecast operator, constructors are used instead. (GLSL 1.051 spec, pg. 24).
Wrong: Vec3 vec = (Vec3) V_eye;
Right: Vec3 vec = Vec3(V_eye);
b) ATI’s GLSL implementation is very picky with types, in particular it doesn’t promote integers to floats, which is a bummer. That comes from a cumbersome part of the spec where you cannot promote integers as floats (not even integer constants): No promotion or demotion of the return type or input argument types is done. (GLSL spec 1.051 pg. 35) and Converting between scalar types is done as the following prototypes indicate… (GLSL spec 1.051 pg. 24).
The problem is not the lack of promotion itself, but how this translates to operating numbers. This problem appears in all the clamp, max and pow functions, as well as when adding subtracting or multiplying integers by floats. So it turns out that you can do float * vec3, but you cannot do int * vec3 or float * int (doh!).
It’s specially painful in the case of pow, where you cannot pow a float to an integer (the function prototypes specify a unique genType for all the parameters).
c) GLSL spec already has a Reflect function, although it’s the reverse negated from the one Tom implemented. Overloading Reflect with Tom’s was giving me grief, so I just commented it out and changed the invocation to match GLSL.
d) In GLSL you cannot alias varying variables: you cannot initialize them in the vertex shader nor in the fragment shader.
varying vec4 Ca = gl_TexCoord[0];
Is wrong, causes a compile error and has to be changed to
vec4 Ca = gl_TexCoord[0];
and when used in the vertex shader, remember to write them out to gl_TexCoord[0] again so the fragment shader receives the proper values.
An even better solution would be to change the application to get the handle for “Ca” instead of hardcoding it to the 0 texture coordinate.
e) Log doesn’t exist, you have to use Log2.
f) Because there’s no promotion/demotion, you cannot multiply a vec3 by a vec4, i.e.
vec4 Ca = gl_TexCoord[0];
vec4 Cd = gl_TexCoord[1];
vec4 Cs = gl_TexCoord[2];
vec3 specular = { 0, 0, 0 };
const vec3 esheen = vec3( 0.1, 0.2, 0.5 ); // Environment sheen
...
Wrong:
specular = specular + pow(sin, (1/breathe*5)) * dot(L, V) * Cs * esheen;
Right:
specular = specular + pow(sin, (1.0/breathe*5.0)) * dot(L, V) * Cs.xyz * esheen;
These are the corrected shaders:
Phong.glsl
vec4 Ca = gl_TexCoord[0];
vec4 Cd = gl_TexCoord[1];
vec4 Cs = gl_TexCoord[2];
vec4 V_eye = gl_TexCoord[3];
vec4 L_eye = gl_TexCoord[4];
vec4 N_eye = gl_TexCoord[5];
/* vec3 reflect(in vec3 N, in vec3 L)
{
return 2*N*dot(N, L) - L;
}*/
void main(void)
{
vec3 V = normalize(vec3(V_eye));
vec3 L = normalize(vec3(L_eye));
vec3 N = normalize(vec3(N_eye));
float diffuse = clamp(dot(L, N), 0.0, 1.0);
vec3 R = -reflect(L, N);
float specular = clamp(pow(dot(R, V), 16.0), 0.0, 1.0);
gl_FragColor = Ca + (Cd*diffuse) + (Cs*specular);
}
blin.glsl
vec4 Ca = gl_TexCoord[0];
vec4 Cd = gl_TexCoord[1];
vec4 Cs = gl_TexCoord[2];
vec4 V_eye = gl_TexCoord[3];
vec4 L_eye = gl_TexCoord[4];
vec4 N_eye = gl_TexCoord[5];
void main(void)
{
vec3 V = normalize(vec3(V_eye));
vec3 L = normalize(vec3(L_eye));
vec3 N = normalize(vec3(N_eye));
float diffuse = clamp(dot(L, N), 0.0, 1.0);
vec3 H = normalize(L + V);
float specular = clamp(pow(dot(N, H), 32.0), 0.0, 1.0);
gl_FragColor = Ca + (Cd*diffuse) + (Cs*specular);
}
rim.glsl
vec4 Ca = gl_TexCoord[0];
vec4 Cd = gl_TexCoord[1];
vec4 Cs = gl_TexCoord[2];
vec4 V_eye = gl_TexCoord[3];
vec4 L_eye = gl_TexCoord[4];
vec4 N_eye = gl_TexCoord[5];
const float edgeWidth = 0.3;
float bias(float value, float b)
{
return (b > 0.0) ? pow(value, log2(b) / log2(0.5)) : 0.0;
}
void main(void)
{
vec3 V = normalize(vec3(V_eye));
vec3 L = normalize(vec3(L_eye));
vec3 N = normalize(vec3(N_eye));
float diffuse = clamp(dot(L, N), 0.0, 1.0);
float edgeScale = bias(1.0 - dot(V, N), edgeWidth);
edgeScale = max(0.7, 4.0*edgeScale);
diffuse = diffuse * edgeScale;
gl_FragColor = Ca + (Cd*diffuse);
}
lambert.glsl
vec4 Ca = gl_TexCoord[0];
vec4 Cd = gl_TexCoord[1];
vec4 Cs = gl_TexCoord[2];
vec4 V_eye = gl_TexCoord[3];
vec4 L_eye = gl_TexCoord[4];
vec4 N_eye = gl_TexCoord[5];
void main(void)
{
vec3 L = normalize(vec3(L_eye));
vec3 N = normalize(vec3(N_eye));
float diffuse = clamp(dot(L, N), 0.0, 1.0);
gl_FragColor = Ca + (Cd*diffuse);
}
sharpspecular.glsl
vec4 Ca = gl_TexCoord[0];
vec4 Cd = gl_TexCoord[1];
vec4 Cs = gl_TexCoord[2];
vec4 V_eye = gl_TexCoord[3];
vec4 L_eye = gl_TexCoord[4];
vec4 N_eye = gl_TexCoord[5];
const float sharpness = 0.2;
void main(void)
{
vec3 V = normalize(vec3(V_eye));
vec3 L = normalize(vec3(L_eye));
vec3 N = normalize(vec3(N_eye));
float diffuse = clamp(dot(L, N), 0.0, 1.0);
vec3 H = normalize(L + V);
float specular = clamp(pow(dot(N, H), 32.0), 0.0, 1.0);
float w = 0.18 * (1.0 - sharpness);
specular = smoothstep(0.72 - w, 0.72 + w, specular);
gl_FragColor = Ca + (Cd*diffuse) + (Cs*specular);
}
thinplastic.glsl
vec4 Ca = gl_TexCoord[0];
vec4 Cd = gl_TexCoord[1];
vec4 Cs = gl_TexCoord[2];
vec4 V_eye = gl_TexCoord[3];
vec4 L_eye = gl_TexCoord[4];
vec4 N_eye = gl_TexCoord[5];
const float sharpness = 0.2;
void main(void)
{
vec3 V = normalize(vec3(V_eye));
vec3 L = normalize(vec3(L_eye));
vec3 N = normalize(vec3(N_eye));
float diffuse = clamp(dot(L, N), 0.0, 1.0);
vec3 H = normalize(L + V);
float specular = clamp(pow(dot(N, H), 32.0), 0.0, 1.0);
float w = 0.18 * (1.0 - sharpness);
specular = smoothstep(0.72 - w, 0.72 + w, specular);
gl_FragColor = Ca + (Cd*diffuse) + (Cs*specular);
}
velvet.glsl
vec4 Ca = gl_TexCoord[0];
vec4 Cd = gl_TexCoord[1];
vec4 Cs = gl_TexCoord[2];
vec4 V_eye = gl_TexCoord[3];
vec4 L_eye = gl_TexCoord[4];
vec4 N_eye = gl_TexCoord[5];
const float backscatter = 0.25;
const float edginess = 4.0;
const float sheen = 0.7;
void main(void)
{
vec3 V = normalize(vec3(V_eye));
vec3 L = normalize(vec3(L_eye));
vec3 N = normalize(vec3(N_eye));
float diffuse = clamp(dot(L, N), 0.0, 1.0);
float cosine = clamp(dot(L, V), 0.0, 1.0);
float shiny = sheen * pow(cosine, 16.0) * backscatter;
cosine = clamp(dot(N, V), 0.0, 1.0);
float sine = sqrt(1.0 - cosine);
shiny = shiny + sheen * pow(sine, edginess) * diffuse;
gl_FragColor = Ca + (Cd*diffuse) + (Cs*shiny);
}
vertex.glsl
const vec4 AMBIENT = vec4( 0.1, 0.1, 0.1, 1.0 );
const vec4 SPECULAR = vec4( 1.0, 1.0, 1.0, 1.0 );
uniform vec4 light;
vec4 Ca = gl_TexCoord[0];
vec4 Cd = gl_TexCoord[1];
vec4 Cs = gl_TexCoord[2];
vec4 V_eye = gl_TexCoord[3];
vec4 L_eye = gl_TexCoord[4];
vec4 N_eye = gl_TexCoord[5];
void main(void)
{
V_eye = gl_ModelViewMatrix * gl_Vertex;
L_eye = (gl_ModelViewMatrix * light) - V_eye;
N_eye = vec4(gl_NormalMatrix * gl_Normal, 1.0);
gl_Position = gl_ProjectionMatrix * V_eye;
V_eye = -V_eye;
Ca = AMBIENT;
Cd = gl_Color;
Cs = SPECULAR;
gl_TexCoord[0] = Ca;
gl_TexCoord[1] = Cd;
gl_TexCoord[2] = Cs;
gl_TexCoord[3] = V_eye;
gl_TexCoord[4] = L_eye;
gl_TexCoord[5] = N_eye;
}
sheen.glsl
vec4 Ca = gl_TexCoord[0];
vec4 Cd = gl_TexCoord[1];
vec4 Cs = gl_TexCoord[2];
vec4 V_eye = gl_TexCoord[3];
vec4 L_eye = gl_TexCoord[4];
vec4 N_eye = gl_TexCoord[5];
const vec3 esheen = vec3( 0.1, 0.2, 0.5 ); // Environment sheen
const vec3 lsheen = vec3( 0.3, 0.4, 0.5 ); // Light sheen
const vec3 gsheen = vec3( 0.4, 0.35, 0.3 ); // Glow sheen
const float breathe = 0.8; // Sheen attenuation
void main(void)
{
vec3 V = normalize(vec3(V_eye));
vec3 L = normalize(vec3(L_eye));
vec3 N = normalize(vec3(N_eye));
float diffuse = clamp(dot(L, N), 0.0, 1.0);
vec3 H = normalize(L + V);
float cos = dot(N, V);
float sin = sqrt(1.0 - pow(cos, 2.0));
vec3 specular = vec3( 0, 0, 0, 1 );
specular = specular + pow(sin, (1.0/breathe*5.0)) * dot(L, V) * Cs.xyz * esheen;
specular = specular + pow(sin, (1.0/breathe*5.0)) * dot(L, N) * Cs.xyz * lsheen;
specular = specular + pow(cos, (breathe*5.0)) * dot(L, N) * Cs.xyz * gsheen;
gl_FragColor = Ca + (Cd*diffuse) + vec4(specular, 1.0);
}