【问题标题】:How to reuse the three.js fragment shader output如何重用three.js片段着色器输出
【发布时间】:2021-08-22 05:14:05
【问题描述】:
我是 three.js 中的新 glsl 着色器,现在尝试在网格纹理上制作简单快速的模糊效果。这是我的片段着色器代码:
void blurh(in vec4 inh, out vec4 outh, int r) {
for(int x = -r; x < r+1; x++) {
float coordx = vUv[0] + float(x) / uResolution[0];
coordx = max(0.0, min(1.0, coordx));
inh += texture2D(uTexture, vec2 (coordx, vUv[1]));
}
outh = inh / float(r + r + 1);
}
void blurv(in vec4 inv, out vec4 outv, int r) {
for(int y = -r; y < r+1; y++) {
float coordy = vUv[1] + float(y) / uResolution[1];
coordy = max(0.0, min(1.0, coordy));
inv += texture2D(uTexture, vec2 (vUv[0], coordy));
}
outv = inv / float(r + r + 1);
}
void main() {
int r = 200; // radius
gl_FragColor = texture2D(uTexture, vUv);
blurh(gl_FragColor, gl_FragColor, r);
blurv(gl_FragColor, gl_FragColor, r);
}
输出结果:
它应该给我一个框模糊,但它只是在垂直方向上模糊。
似乎垂直模糊功能没有使用水平模糊结果作为输入。
所以第一个问题是,如何重用水平模糊函数输出作为垂直模糊函数的输入?其次,如何在片段着色器中存储/保存一些变量以供以后使用?
【问题讨论】:
标签:
javascript
three.js
glsl
fragment-shader
【解决方案1】:
请注意,存储库已经提供了模糊着色器。所以你可以使用后处理管道来达到预期的效果:
let camera, scene, composer;
let mesh;
init();
animate();
function init() {
camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 0.01, 10);
camera.position.z = 1;
scene = new THREE.Scene();
const geometry = new THREE.BoxGeometry(0.2, 0.2, 0.2);
const material = new THREE.MeshNormalMaterial();
mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
composer = new THREE.EffectComposer(renderer);
const renderPass = new THREE.RenderPass(scene, camera);
const effectHBlur = new THREE.ShaderPass(THREE.HorizontalBlurShader);
const effectVBlur = new THREE.ShaderPass(THREE.VerticalBlurShader);
effectHBlur.uniforms['h'].value = 1 / window.innerWidth;
effectVBlur.uniforms['v'].value = 1 / window.innerHeight;
composer.addPass(renderPass);
composer.addPass(effectHBlur);
composer.addPass(effectVBlur);
}
function animate() {
requestAnimationFrame(animate);
mesh.rotation.x += 0.01;
mesh.rotation.y += 0.02;
composer.render();
}
body {
margin: 0;
}
<script src="https://cdn.jsdelivr.net/npm/three@0.129/build/three.js"></script>
<script src="https://cdn.jsdelivr.net/npm/three@0.129/examples/js/postprocessing/EffectComposer.js"></script>
<script src="https://cdn.jsdelivr.net/npm/three@0.129/examples/js/postprocessing/ShaderPass.js"></script>
<script src="https://cdn.jsdelivr.net/npm/three@0.129/examples/js/postprocessing/RenderPass.js"></script>
<script src="https://cdn.jsdelivr.net/npm/three@0.129/examples/js/shaders/HorizontalBlurShader.js"></script>
<script src="https://cdn.jsdelivr.net/npm/three@0.129/examples/js/shaders/VerticalBlurShader.js"></script>
<script src="https://cdn.jsdelivr.net/npm/three@0.129/examples/js/shaders/CopyShader.js"></script>
如果您不想使用效果器,则必须使用普通渲染目标。含义:
- 首先将场景渲染到渲染目标中(美丽通道)
- 应用水平模糊并渲染到下一个渲染目标
- 应用垂直模糊并渲染到屏幕
所以你必须将你当前的着色器一分为二。