上次给球体添加了卡通风格着色器之后觉得还少些什么,仔细观察网上卡通风格的游戏发现,卡通风格的3D任务往往除了明显不平滑过渡的色块以外,还都有着黑色描边,这次我们就来修改着色器实现描边的效果。
描边特效可以通过很多方法来实现,比如:判断每个面片的朝向,当一条棱既出现在一个面片的正面又出现在反面时,说明该楞是分界线,将其涂黑即可。或者将每个点沿着法线方向延伸一定距离,相当于一个放大了的模型,然后将其涂黑,第二次正常绘制,就会出现黑边,这里面就要用到二次绘制了~最后再说我们使用的方法:计算每一个片元的法线与视线方向的夹角,当其大于阈值时将其涂黑,这样方便快捷~(只能对于平滑过渡的物体使用,当物体表面过渡不平滑时描边会很小几乎看不到)。
这次直接贴着色器的代码,其他与上次的代码的一样,(http://blog.csdn.net/srk19960903/article/details/67645302)。主要的区别在于片元着色器这里,我们增加了浮点型一个变量dir,它的结果是视线方向映射到法线上的长度,也就是说该点越靠近边缘,距离视线方向越远,这个值也就越小(平滑物体)。当该值小于一定程度时则说明这个片元处在边缘上,就将该片元的颜色值赋值为零也就是黑色。否则按照正常的卡通着色器赋值,这样就完成了卡通风格的着色器~
<script id="fish-fragmentShader" type="x-shader/x-vertex"> uniform vec3 light; varying vec3 vNormal; uniform vec3 color; void main() { float diffuse = dot(normalize(light), vNormal); float dir = length(vNormal * vec3(0.0, 0.0, 1.0)); if (dir < 0.5) { dir = 0.0; gl_FragColor = vec4(dir, dir, dir, 1.0); } else { if (diffuse > 0.8) { diffuse = 1.0; } else if (diffuse > 0.5) { diffuse = 0.6; } else if (diffuse > 0.2) { diffuse = 0.4; } else { diffuse = 0.2; } gl_FragColor = vec4( color* diffuse, 1.0); } } </script>下面是实现后的图片,还是很有卡通的感觉~哈哈
最后github地址:https://github.com/StringKun/ThreeJSToonShader/tree/master/ThreeJSshader2