threejs 后期处理扫描
目录
前言
填坑。因为后期处理没有世界坐标,本文利用深度与相机vp逆矩阵还原,实现扫描功能。
一、获取世界坐标
1.传入透视相机的vp逆矩阵
let VPMatrix4x4_inverse = this.camera.projectionMatrixInverse.clone().premultiply( this.camera.matrixWorld.clone() );
this.customScanUniforms.VPMatrix4x4_inverse.value = VPMatrix4x4_inverse
2.获取并处理uv
vs:
varying vec2 vUv;
...
main{
vUv = uv;
...
}
fs:
varying vec2 vUv;
main{
vec2 vUv_ = ( vUv * 2.0 ) - 1.0;
...
}
3.深度获取
获取的透视相机的深度并不是线性的,所以可以利用readDepth()获取处理的线性深度
fs:
#include <packing>
uniform sampler2D sceneColorBuffer;
uniform sampler2D depthBuffer;
uniform sampler2D normalBuffer;
uniform float cameraNear;
uniform float cameraFar;
uniform float cameraFov;
uniform vec4 screenSize;
uniform vec3 myLight;
uniform vec3 myCamera;
uniform float myTime;
varying vec3 v_normal;// 法线数据
uniform mat4 VPMatrix4x4_inverse;//相机vp逆矩阵
...
// 帮助获取线性深度
float readDepth (sampler2D depthSampler, vec2 coord) {
float fragCoordZ = texture2D(depthSampler, coord).x;
float viewZ = perspectiveDepthToViewZ( fragCoordZ, cameraNear, cameraFar );
return viewZToOrthographicDepth( viewZ, cameraNear, cameraFar );
}
float getPixelDepth(int x, int y) {
return readDepth(depthBuffer, vUv + screenSize.zw * vec2(x, y));
}
main{
float depth = getPixelDepth(0,0);//获取的线性深度
vec2 vUv_ = ( vUv * 2.0 ) - 1.0;
float baseDepth = texture2D(depthBuffer,vUv).x;//非线性深度
...
}
4.ndc坐标求世界坐标
vec4 ndc = vec4( vUv_.x , vUv_.y , (baseDepth*2.0-1.0) , 1.0 );
vec4 worldPos = VPMatrix4x4_inverse * ndc;
worldPos /= worldPos.w;
二、实现扫描
有了世界坐标实现扫描就非常轻松了
这里传入时间,利用零点坐标与各点的距离判断是否为扫描点。
//传入扫描时间
this.customScanUniforms.myTime.value = this.myTime
//扫描
fs:
main{
...
if(depth<0.99 && myTime>0.0){
// float mydistance = distance(vec3(0,0,0),vec3(worldPos.x,worldPos.y,worldPos.z));
float mydistance = length(vec3(worldPos.x,worldPos.y,worldPos.z));
if( myTime*cameraFar > mydistance && mydistance > myTime*cameraFar/2.0 ){
sceneColor3 = mix(vec3(1,0,0),sceneColor3,0.2);
}
}
}
效果