描边效果是游戏里面非常常用的一种效果,一般是为了凸显游戏中的某个对象,会给对象增加一个描边效果。
例如最常见的LOL中的防御塔,我们把鼠标移动到塔上,就会有很明显的描边效果:
简单的描边效果原理:
我们的描边效果,肯定就是要让模型更“胖”一点,能够把我们原来的大小包裹住;微观一点来看,一个面,如果我们让它向外拓展,而我们指的外,也就是这个面的法线所指向的方向,那么就让这个面朝着法线的方向平移一点;再微观一点来看,对于顶点来说,也就是我们的vertex shader真正要写的内容了,我们正常计算顶点的时候,传入的vertex会经过MVP变换,最终传递给fragment shader,那么我们就可以在这一步让顶点沿着法线的方向稍微平移一些。然后先渲染“胖”的模型,再在相同位置渲染原模型将两者重复部分遮挡,就显示出描边效果了。
下面是着色器的代码:
THREE.OutLineShader={
vertexShader: [
"uniform float offset;",
"void main() {",
"vec4 pos = modelViewMatrix * vec4( position + normal * offset, 1.0 );",
"gl_Position = projectionMatrix * pos;",
"}"
].join("\n"),
fragmentShader: [
"void main(){",
"gl_FragColor = vec4( 1.0, 0.0, 0.0, 1.0 );",
"}"
].join("\n")
};
接下来只需创建着色器材质来创建轮廓效果的网格体对象即可,代码如下:
let geometry= new THREE.TorusKnotGeometry(50,10,50,20);
//轮廓着色器
outShader=THREE.OutLineShader;
//着色器材质
matShader=new THREE.ShaderMaterial({
uniforms: {
offset:{
type: 'f', //指定变量类型为float
value:1.0 //偏移值
}
},
vertexShader: outShader.vertexShader,
fragmentShader: outShader.fragmentShader
} );
//outlineMesh
let outlineMesh=new THREE.Mesh(geometry,matShader);
outlineScene.add(outlineMesh);
下面说一下如何控制渲染顺序,使“胖”的模型先渲染,即使原模型始终在“胖”的模型之上显示。若向让一个物体始终显示在另一个物体之上,可通过设置场景中物体的渲染顺序来实现,需要为每一个物体设置渲染顺序
。
可以通过下面的方法设置场景中物体的渲染顺序:
renderer.sortObjects = true;//若为false,物体的渲染顺序将会由他们添加到场景中的顺序所决定
然后对场景中物体设置object.renderOrder 指定它的渲染顺序。
而如果此时场景中物体过多,而只想要某一个物体最后渲染,显而易见这样的方法比较麻烦。如果你想让一些物体“在顶部”或“在前面”渲染,你还可以通过创建两个场景来实现 - 第一个场景是你的常规场景,第二个场景包含你想要在顶部的物体。
笔者使用的第二种方法,以下是render()函数中执行的操作:
//清除上一帧画面
renderer.clear();
//渲染轮廓场景
renderer.render(outlineScene,outlineCamera);
//清楚深度缓冲
renderer.clearDepth();
//渲染物体场景
renderer.render(scene,camera);
案例效果图:
案例源代码:https://github.com/NCQuan/three.js-object-of-stroke/blob/master/stroke/outline.html