先贴出shader 吧 等有时间了 来阐述原理
// vertex shader //varying vec3 ViewPosition; //varying vec3 Normal; varying vec3 Vertex_UV; varying vec3 Vertex_Normal; varying vec3 Vertex_LightDir; varying vec3 Vertex_EyeVec; void main(void) { gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; Vertex_UV = gl_MultiTexCoord0.xyz ; Vertex_Normal = gl_NormalMatrix*gl_Normal; vec4 view_vertex = gl_ModelViewMatrix*gl_Vertex; Vertex_LightDir = (gl_LightSource[0].position - view_vertex).xyz; Vertex_EyeVec = (-view_vertex).xyz ; /* vec4 MVM = (gl_ModelViewMatrix*gl_Vertex); ViewPosition = MVM.xyz / MVM.w; Normal = normalize(gl_NormalMatrix*gl_Normal); */ }
//uniform sampler2D tex0; // color map uniform sampler2D normalMap; // normal map //uniform int LightNum; varying vec3 Vertex_UV; varying vec3 Vertex_Normal; varying vec3 Vertex_LightDir; varying vec3 Vertex_EyeVec; //out vec4 Out_Color; mat3 cotangent_frame(vec3 N, vec3 p, vec2 uv) { // get edge vectors of the pixel triangle vec3 dp1 = dFdx( p ); vec3 dp2 = dFdy( p ); vec2 duv1 = dFdx( uv ); vec2 duv2 = dFdy( uv ); // solve the linear system vec3 dp2perp = cross( dp2, N ); vec3 dp1perp = cross( N, dp1 ); vec3 T = dp2perp * duv1.x + dp1perp * duv2.x; vec3 B = dp2perp * duv1.y + dp1perp * duv2.y; // construct a scale-invariant frame float invmax = inversesqrt( max( dot(T,T), dot(B,B) ) ); return mat3( T * invmax, B * invmax, N ); } vec3 perturb_normal( vec3 N, vec3 V, vec2 texcoord ) { // assume N, the interpolated vertex normal and // V, the view vector (vertex to eye) vec3 map = texture(normalMap, texcoord ).xyz; map = map * 255./127. - 128./127.; mat3 TBN = cotangent_frame(N, -V, texcoord); return normalize(TBN * map); } void main(void){ vec2 uv = Vertex_UV.xy; vec3 N = normalize(Vertex_Normal); vec3 L = normalize(Vertex_LightDir); vec3 V = normalize(Vertex_EyeVec); vec3 PN = perturb_normal(N, V, uv); //float lambertTerm = dot(PN, L); vec4 intensity=vec4(0.0,0.0,0.0,0.0); // 最终的颜色 vec3 vDir,lDir,hDir; float NdotL,NdotHV; hDir = normalize(V + L) ; NdotL = max(dot(PN, L), 0.0); NdotHV = max(dot(PN, hDir), 0.0); intensity+= gl_LightSource[0].ambient * 0.5 ; intensity+= gl_LightSource[0].diffuse * NdotL * 0.3 ; if(NdotL!=0) intensity += gl_LightSource[0].specular * NdotL * pow(NdotHV,30); gl_FragColor = intensity; }
最近做subsurface scattering ,发现normal mapping 根本加不上,因为SSS实质相当于对表面做了个平滑,细节再加也会被平滑掉。
后来想着把扰动后的normal 直接加在最终的SSS效果上,不过这样有个问题就是本来的法向图必须增强,因为在最终的效果上叠加法向图效果比较弱