Three.js实现最简单的xray透视效果
前几天公司领导一直让做个透视效果,此时想到了xray效果,翻阅网上尚未找到用WebGL实现的Xray(可能我太笨木有找到),倒是许多Unity3D实现Xray,毕竟这东西在游戏中用的会多一点。实现Xray的主题思想很简单,就是被遮挡区域特效处理,未遮挡区域正常绘制即可。在这里我们采用Unity3D绘制Xray原理即两个pass,在这里我两个pass处理成两个相同的mesh运用不同的材质(性能浪费,毕竟不需要所有的Mesh具有Xray效果。。。。)。
思路(Unity3D)
实现这个效果需要两个pass
1. 绘制被遮挡部分,即 深度测试 Greater ,且不写入 深度缓冲区(防止印象其他物体的深度对比),剩下的 xray效果就比较容易,同一 空间 下通过 点积 处理。
2. 正常绘制,即 深度测试 LEqual ,且写入 深度缓冲区(正常与其他物体遮挡)。
改成WebGL:
pass1
//第一个pass渲染被遮挡部分,采用顶点法向量与相加法线关系越靠近物体边缘颜色越深,即float rim = 1 - saturate(dot(normalize(i.normal),normalize(i.viewDir)));
materialXay=new ShaderMaterial({
uniforms:{},
vertexShader:'',
fragmentShader:'',
transparent:true,
depthWrite:false,
depthFunc:GreaterDepth
});
pass2
//第二个pass正常渲染,会自动屏蔽被遮挡的部分
materialNormal=new ShaderMaterial({
uniforms:{},
vertexShader:'',
fragmentShader:'',
transparent:false,
depthWrite:true,
depthFunc:LessEqualDepth
});
示例代码
pass1的顶点着色器:
varying vec3 vNormal;
varying vec3 vPositionNormal;
void main()
vNormal = normalize( normalMatrix * normal ); // 转换到视图空间
vPositionNormal = normalize(( modelViewMatrix * vec4(position, 1.0) ).xyz);
gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
}
pass1的片源着色器:
uniform vec3 glowColor;
uniform float bias;
uniform float power;
uniform float scale;
varying vec3 vNormal;
varying vec3 vPositionNormal;
void main()
float a = pow( bias + scale * abs(dot(vNormal, vPositionNormal)), power );
gl_FragColor = vec4( glowColor, a );
}
该段着色器效果发光效果参考:
最终pass1的材质:
let uniformsXary ={
scale: { type: "f", value: -1.0},
bias: { type: "f", value: 1.0},
power: { type: "f", value: 1.4 },
glowColor: { type: "c", value: new THREE.Color(0x00ffff) }
let materialXay=new THREE.ShaderMaterial({
uniforms:uniformsXary,
vertexShader:document.getElementById( 'vertexshader').textContent,
fragmentShader: document.getElementById( 'fragmentshader').textContent,
transparent:true,
depthWrite:false,
depthTest:true,
depthFunc:THREE.GreaterDepth
});
mesh示例:
var loader = new FBXLoader();
loader.load( './Asset/fbx/Samba Dancing.fbx', function ( object ) {
object.traverse( function ( child ) {
if ( child.isMesh ) {
//为了解决z冲突
let materialnormal=child.material;
materialnormal.polygonOffset = true;
materialnormal.depthTest = true;
materialnormal.polygonOffsetFactor = 1;
materialnormal.polygonOffsetUnits = 1.0;
child.castShadow = true;
child.receiveShadow = true;
let sphereGeomXay=child.geometry.clone();
let meshXay=new THREE.Mesh(sphereGeomXay,materialXay);