My brother has shown me a sculpting application with ability to assign materials from images and render them in real-time. Since they looked so great, just like raytraced(after briefly blaming the developers of the application of witchcraft), I started researching the subject and ended up writing my own implementation.
Matcap
Matcap(Material-Capture), is a technique of combining material properties and lighting information in an image. Basically image is interpreted as a hemi-sphere, each point on sphere is matched against a normal. When object is rendered with matcap material, normals are calculated for each fragment, and that information used to map matcap image and get fragment color.
Without actually making any lighting or reflection calculation in the shader, we are using a precalculated table, so very sophisticated looking rendering with reflection, subsurface scattering, specularity, becomes possible.
Limitations
However, since matcap is visual information of an object, seen in a certain camera angle and certain ligthing conditions, the material itself is actually not lit, meaning no actual lighting is done on the shader, the light is fixed in related to camera. When your camera moves, light also moves with it.
Another limitation of matcap is not being able to use any kind of texture on MatCap image. Since matcap mapping is in relation to camera any texture you apply on to matcap material will look like environment mapping.
Shaders
In vertex shader, we first get the vertex normal attribute and move it into model(world) space and assign it to an interpolated vector.
In fragment shader, the interpolated value of the normal is transformed into camera space and normalize. Each component of normal now in [-1,1] inverval, we move them into texture space [0,1] and ignore Z value.
Vertex shader:
vNormal = normalize(vec3(world * vec4(normal, 0.0))); // Normal in model space
Fragment shader:
// Move normal to view space
highp vec2 muv = vec2(view * vec4(normalize(vNormal), 0))*0.5+vec2(0.5,0.5);
// read texture inverting Y value
gl_FragColor = texture2D(matcapTexture, vec2(muv.x, 1.0-muv.y));
Source code & Demo
You try matcap materials in demo I wrote here. You can also obtain source code from my Github repo, or just view source of the page.
Comments
comments powered by Disqus