我正在尝试向场景添加高斯模糊。我正在使用这个 GLSL 着色器:
uniform sampler2D tDiffuse;
uniform int uKernel;
uniform float uSigma;
uniform vec2 uDirection;
uniform float uStrength;
uniform float uDirectionalResolution;
varying vec2 v_Uv;
float gaussianPdf(in float x,in float sigma){
return(.39894/sigma)*exp(-.5*x*x/(sigma*sigma));
}
float parabola(float x,float k){
return pow(4.*x*(1.-x),k);
}
void main(){
float weightSum=gaussianPdf(0.,uSigma);
vec4 t=texture2D(tDiffuse,v_Uv);
vec3 diffuseSum=t.rgb*weightSum;
float invSize=1./uDirectionalResolution;
float focus=distance(vec2(.5),v_Uv);
focus=smoothstep(0.,.7,focus);
for(int i=1;i<uKernel;i++){
float x=float(i);
float w=gaussianPdf(x,uSigma);
vec2 offset=uDirection*invSize*x*uStrength*focus;
vec4 sample1=texture2D(tDiffuse,v_Uv+offset);
vec4 sample2=texture2D(tDiffuse,v_Uv-offset);
diffuseSum+=(sample1.rgb+sample2.rgb)*w;
weightSum+=2.*w;
}
gl_FragColor=vec4(diffuseSum/weightSum,1.);
}
当您提供图像作为 tDiffuse 纹理时,它适用于图像,但我试图将其添加为后处理效果。我尝试获取相机的 renderTarget 并将该纹理作为 tDiffuse 传递,但这在计算上太昂贵了:(
这是反应代码:
import vert from "./vertex.glsl"
import frag from "./fragment.glsl"
function BlurShader() {
const { gl, size, scene, camera } = useThree();
const uniforms = useMemo(() => ({
time: { value: 0.0 },
uKernel: { value: 13 },
uSigma: { value: 3 },
tDiffuse: { value: null },
uStrength: { value: 1 },
uDirection: { value: new THREE.Vector2(1, 1) },
uDirectionalResolution: { value: 512 },
}), [])
return (
<>
</>
)
}
export default function Test() {
return (
<div className='h-full w-full absolute'>
<Canvas camera={{ fov: 75, near: 0.01, far: 50, position: [0, 0, 1] }}>
<color attach="background" args={["black"]} />
<OrbitControls />
<Particles />
<BlurShader />
</Canvas>
</div>
)
}
有没有一种方法可以在不执行相机 renderTarget 的情况下实现此目的?或者有其他更有效的方法吗?
我采用了简单的方法,使用react- Three / drei中的“useFBO”创建了我想要的效果
function BlurShader() {
const FBOTarget = useFBO(1024, 1024, { stencilBuffer: false, minFilter: THREE.LinearFilter, magFilter: THREE.NearestFilter });
const materialRef = useRef();
const uniforms = useMemo(() => ({
time: { value: 0.0 },
uKernel: { value: 13 },
uSigma: { value: 6 },
tDiffuse: { value: null },
uStrength: { value: 2.5 },
uDirection: { value: new THREE.Vector2(1, 1) },
uDirectionalResolution: { value: 512 },
resolution: { value: new THREE.Vector2(1024, 1024) },
}), [])
useFrame((state) => {
state.gl.setRenderTarget(FBOTarget);
state.gl.render(state.scene, state.camera);
state.gl.setRenderTarget(null);
materialRef.current.uniforms.tDiffuse.value = FBOTarget.texture;
})
return (
<>
<mesh position={[0, 0, 0.2]}>
<planeGeometry args={[2, 1]} />
<shaderMaterial
ref={materialRef}
fragmentShader={frag}
vertexShader={vert}
uniforms={uniforms}
/>
</mesh>
<Box args={[0.2, 0.2, 0.2]} position={[0.5, 0.2, 0]} >
<meshBasicMaterial color={"green"} />
</Box>
<Box args={[0.2, 0.2, 0.2]} position={[0.1, 0, -0.1]} >
<meshBasicMaterial color={"yellow"} />
</Box>
<Box args={[0.2, 0.2, 0.2]} position={[-0.7, 0.2, 0]} >
<meshBasicMaterial color={"red"} />
</Box>
<Box args={[0.2, 0.2, 0.2]} position={[-0.4, -0.3, -0.3]} >
<meshBasicMaterial color={"blue"} />
</Box>
</>
)}
但我仍然不知道如何将其应用到相机而不是飞机上。 也许将其渲染到屏幕外,然后再次渲染到相机,或者使用effectComposer?