MatCap Shader

Hi, I would like to translate a MatCap shader to jMonkey Engine (GLSL). But I have some troubles.

The shader is used seldom in gamedev, but it’s used in blender, zbrush… and it will be very useful for scrollshooters to imitate different materials like glass, gold, metals, toon styles…

The shader does not use any lights… only one texture(matcap) and a normal map texture(if a model has one). So, it’s good for productivity.
The shader uses model’s normals/tangets/binormals and screen coordinates (as far as I understand).

http://dl.dropbox.com/u/26887202/123/jme_blender/matcap.png – here is a screenshot of the shader.

http://dl.dropbox.com/u/26887202/123/jme_blender/matcap_shader.blend – here is a blender2.5 test file you can have a try.

I found the shader in Unity, but it’s written with cg language.
http://forum.unity3d.com/threads/39500-I-found-out-how-to-do-Zbrush-matcap-shading-in-Unity.
http://www.unifycommunity.com/wiki/index.php?title=MatCap

I also found Sculptris pragram which uses MatCaps:

vertex shader


/*
 
uniform vec3 light1_dir;
 
uniform vec3 light2_dir;
 
uniform vec3 observer_pos;
 
uniform float object_invscale;
 
*/
 
uniform float texturesize;
 
varying vec3 normal;
 
varying vec3 cull_normal;
 
varying vec4 color;
 
varying vec3 tangent;
 
varying vec3 binormal;
 
attribute vec3 app_Tangent;
 
void main()
 
{
 
//    normal=gl_Normal.xyz;
 
//    position=gl_Vertex.xyz*object_invscale;
 
    color=gl_Color;
 
//    gl_TexCoord[0]=gl_MultiTexCoord0;
 
//    gl_TexCoord[0]=gl_MultiTexCoord0-vec4(0.5/256, 0.5/256, 0, 0); // compensate for bumpmap emboss offset - TODO: uniform for texture size
 
//    gl_TexCoord[0]=gl_MultiTexCoord0-vec4(0.5/512, 0.5/512, 0, 0); // compensate for bumpmap emboss offset - TODO: uniform for texture size
 
//    gl_TexCoord[0]=gl_MultiTexCoord0-vec4(0.5/1024, 0.5/1024, 0, 0); // compensate for bumpmap emboss offset - TODO: uniform for texture size
 
    gl_TexCoord[0]=gl_MultiTexCoord0-vec4(0.5/texturesize, 0.5/texturesize, 0, 0); // compensate for bumpmap emboss offset
 
    gl_TexCoord[1]=gl_MultiTexCoord0; // no uv compensation for colortexture
 
    gl_Position=ftransform();
 
    normal=normalize(gl_NormalMatrix*gl_Normal.xyz);
 
    vec3 tpos=(gl_ModelViewMatrix*gl_Vertex).xyz;
 
    vec3 nm_z=normalize(tpos);
 
    vec3 nm_x=cross(nm_z, vec3(0,1,0));
 
    vec3 nm_y=cross(nm_x, nm_z);
 
    cull_normal=vec3(dot(normal, nm_x), dot(normal, nm_y), dot(normal, nm_z));
 
    tangent=normalize(gl_NormalMatrix*app_Tangent);
 
    binormal=cross(normal, tangent);
 
//    binormal=normalize(cross(normal, tangent));
 
//    tangent=cross(binormal, normal);
 
}

fragment shader


uniform sampler2D materialtex;
 
uniform sampler2D normaltex;
 
uniform sampler2D colortex;
 
uniform float backfaces;
 
/*
 
varying vec3 light1_vector;
 
varying vec3 light2_vector;
 
varying vec3 eye_vector;
 
*/
 
varying vec3 normal;
 
varying vec3 cull_normal;
 
varying vec3 tangent;
 
varying vec3 binormal;
 
varying vec4 color;
 
//varying vec3 position;
 
//varying vec2 texcoords;
 
vec3 nnormal;
 
void main()
 
{
 
    vec3 tnormal=texture2D(normaltex, gl_TexCoord[0].st).xyz;
 
    tnormal=(tnormal-vec3(0.5, 0.5, 0.5))*2.0;
 
    nnormal=normalize(tangent*tnormal.x + binormal*tnormal.y + normal*tnormal.z);
 
    // overlay vertex color (selection, mask)
 
//    outcolor+=color;
 
    vec2 lightmap_coords=nnormal.xy*0.495+vec2(0.5, 0.5);
 
    lightmap_coords.y*=-1.0;
 
    vec4 shade=texture2D(materialtex, lightmap_coords);
 
    vec4 color=texture2D(colortex, gl_TexCoord[1].st);
 
    vec4 multfactor=shade*2;
 
    vec4 screenfactor=multfactor-vec4(1,1,1,1);
 
    multfactor=min(multfactor, vec4(1,1,1,1));
 
    screenfactor=max(screenfactor, vec4(0,0,0,0));
 
    color=vec4(1,1,1,1)-(vec4(1,1,1,1)-color)*(vec4(1,1,1,1)-screenfactor);
 
    gl_FragColor=color*multfactor;
 
//    gl_FragColor=color;
 
    if(backfaces>0.5 && normalize(cull_normal).z>0.07) // backfacing
 
    {
 
//        gl_FragColor*=0.3;
 
//        gl_FragColor.w=1.0;
 
        float c=(gl_FragColor.x+gl_FragColor.y+gl_FragColor.z)*0.1;
 
        gl_FragColor=vec4(c, c, c, 1);
 
    }
 
//        gl_FragColor=vec4(0.1, 0.1, 0.1, 1);
 
}

So, I cannot understand how to make this thing in fragment shader? What is “normaltex”? There are only two textures (matcap, normal map), but in sculptris there are three texture2D samplers - materialtex, normaltex, colortex.


    vec3 tnormal=texture2D(normaltex, gl_TexCoord[0].st).xyz;
 
    tnormal=(tnormal-vec3(0.5, 0.5, 0.5))*2.0;
 
    nnormal=normalize(tangent*tnormal.x + binormal*tnormal.y + normal*tnormal.z);
 
    // overlay vertex color (selection, mask)
 
//    outcolor+=color;
 
    vec2 lightmap_coords=nnormal.xy*0.495+vec2(0.5, 0.5);
 
    lightmap_coords.y*=-1.0;
 
    vec4 shade=texture2D(materialtex, lightmap_coords);
 
    vec4 color=texture2D(colortex, gl_TexCoord[1].st);
 
    vec4 multfactor=shade*2;
 
    vec4 screenfactor=multfactor-vec4(1,1,1,1);
 
    multfactor=min(multfactor, vec4(1,1,1,1));
 
    screenfactor=max(screenfactor, vec4(0,0,0,0));
 
    color=vec4(1,1,1,1)-(vec4(1,1,1,1)-color)*(vec4(1,1,1,1)-screenfactor);
 
    gl_FragColor=color*multfactor;

Thanks.

I solved it! You can find my MatCap glsl shader here:
http://code.google.com/p/jme-glsl-shaders/

This topic was automatically closed 183 days after the last reply. New replies are no longer allowed.