I'm writing a WebGL code in fragment shader for bump maps. I have interpolated position (pos) normal (nrm) and UVs (vuv), so I use derivatives to get positions and height texels on neighbor pixels, then calculate slopes in both x and y directions and then take slope normal. Then I rotate nrm by the angle between the slope normal and unmodified surface normal. Here's the code I have so far:
vec2 nuvx = vuv + dFdx(vuv);
vec2 nuvy = vuv + dFdy(vuv);
vec3 htex = vec3(
texture2D(bmap, nuvx).g,
texture2D(bmap, nuvy).g,
texture2D(bmap, vuv).g
);
vec2 hdif = vec2(htex.x - htex.z, htex.y - htex.z);
if(abs(hdif.x) > 0.002 || abs(hdif.y) > 0.002) {
vec3 posdx = dFdx(pos);
vec3 posdy = dFdy(pos);
vec3 facenorm = normalize(cross(posdx, posdy));
vec2 hdifsc = bmfact * hdif;
vec3 slopedx = posdx + facenorm * hdifsc.x;
vec3 slopedy = posdy + facenorm * hdifsc.y;
vec3 slope = normalize(cross(slopedx, slopedy));
vec4 q = quaternFromVects(facenorm, slope);
nrm = quaternRotate(nrm, q);
}
vec4 quaternFromVects (vec3 v1, vec3 v2) {
vec3 qe = normalize(cross(v1, v2));
float th = acos(dot(v1, v2)) / 2.0;
float sine = sin(th);
return vec4(cos(th), qe * sine);
}
vec3 quaternRotate (vec3 v, vec4 q) { // q[0] = w
vec4 q2 = q * q;
vec3 q0q123 = q.x * q.yzw;
vec2 q1q23 = q.y * q.zw;
float q2q3 = q.z * q.w;
mat3 mrot;
mrot[0] = vec3(q2.x + q2.y - q2.z - q2.w, 2.0 * (q0q123.z + q1q23.x), 2.0 * (q1q23.y - q0q123.y));
mrot[1] = vec3(2.0 * (q1q23.x - q0q123.z), q2.x - q2.y + q2.z - q2.w, 2.0 * (q0q123.x + q2q3));
mrot[2] = vec3(2.0 * (q0q123.y + q1q23.y), 2.0 * (q2q3 - q0q123.x), q2.x - q2.y - q2.z + q2.w);
return mrot * v;
}
It looks like it's working but I still wanted to ask:
- does this approach make sense?
- do I make things more complex than they need to be, maybe these is a way to simplify this code?
thank you!