添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
Three.js实现最简单的xray透视效果

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);