Ways to recycle the output of the three.js fragment shader

Recently delving into GLSL shaders in three.js, I am currently experimenting with creating a simple and efficient blur effect on a mesh texture. Below is the fragment shader code I have been working on:

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);
}
the resulting output: I was expecting to achieve a box blur effect, however, it seems that the blur is only happening in the vertical direction. It appears that the vertical blur function is not utilizing the horizontal blur result as an input. Therefore, my first question is, how can I reuse the output of the horizontal blur function as the input for the vertical blur function? Additionally, how can I save/store variables in the fragment shader for future use?

Answer №1

Take note that the repository already includes blur shaders. Utilize the post-processing pipeline to achieve the desired effect:

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/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="71051903141431415f404348">[email protected]</a>/build/three.js"></script>
<script src="https://cdn.jsdelivr.net/npm/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="c0b4a8b2a5a580f0eef1f2f9">[email protected]</a>/examples/js/postprocessing/EffectComposer.js"></script>
<script src="https://cdn.jsdelivr.net/npm/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="b1c5d9c3d4d4f1819f808388">[email protected]</a>/examples/js/postprocessing/ShaderPass.js"></script>
<script src="https://cdn.jsdelivr.net/npm/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="36425e44535376061807040f">[email protected]</a>/examples/js/postprocessing/RenderPass.js"></script>
<script src="https://cdn.jsdelivr.net/npm/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="f18599839494b1c1dfc0c3c8">[email protected]</a>/examples/js/shaders/HorizontalBlurShader.js"></script>
<script src="https://cdn.jsdelivr.net/npm/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="ea9e82988f8faadac4dbd8d3">[email protected]</a>/examples/js/shaders/VerticalBlurShader.js"></script>
<script src="https://cdn.jsdelivr.net/npm/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="4f3b273d2a2a0f7f617e7d76">[email protected]</a>/examples/js/shaders/CopyShader.js"></script>

If you prefer not to use the effect composer, you will need to work with plain render targets. This involves:

  • Rendering the scene into a render target first (beauty pass)
  • Applying the horizontal blur and rendering to the next render target
  • Applying the vertical blur and rendering to the screen

Therefore, you must divide your current shader into two separate parts.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Attempting to input a parameter into a personalized directive

Currently developing a small search application using Elasticsearch and AngularJS. The app consists of 2 pages: home and results page. However, I am encountering an issue with my custom search directive where I need to pass the value of a service into it. ...

Discovering the largest value with arrays in javascript

My code is functioning as expected for single-digit numbers but encounters issues with two or three-digit numbers. I want to stick to this approach without utilizing the math max function. The primary issue lies in only considering the first digit of a tw ...

Transfer information from a Vue function to an external JSON document

I would like to store the data for my Vue project in an external JSON file instead of within the Vue function itself. I attempted to retrieve data from an external file using the code below, but encountered issues, possibly due to a conflict with the "ite ...

When using React.js with Leaflet, ensure that the useEffect hook is only run on Mount when in the

I have encountered an issue where I need to ensure that the useEffect Hook in React runs only once. This is mainly because I am initializing a leaflet.js map that should not be initialized more than once. However, anytime I make changes to the component&a ...

Tips for sorting through various elements or items

How can I improve my filtering function to select multiple items simultaneously, such as fruits and animals, or even 3+ items? Currently, it only allows selecting one item at a time. I attempted using , but it had bugs that displayed the text incorrectly. ...

Define default array values in Mongoose schemas using Node.js

My model definition includes: appFeatures: [{ name: String, param : [{ name : String, value : String }] }] I am looking to assign a default value to appFeatures, such as: name: 'feature', para ...

Please consider opening in a new tab rather than a new window

<a href='#' onclick="loadpage();">[RANDOM PAGE]</a> Whenever this code is clicked, the following function gets executed. function loadpage(){ $.ajax ({ type: "POST", url: "fetchpage.php", data: "showpage=1", success: function(msg) { ...

Is this being used to store a variable within a function?

Is there a practical reason for not using let total in the scenario below? I understand that the purpose is to illustrate how arrow functions address the this issue, but are there real-world use cases where this solution is beneficial? function sum() { ...

Route functions cannot be hoisted in the Express framework

Can someone shed light on why my Express routes aren't hoisted? I keep encountering this error: throw new TypeError('Router.use() requires middleware functions'); The error is not present in the following file: var express = requir ...

Using TypeScript and the `this` keyword in SharePoint Framework with Vue

I'm currently developing a SharePoint Framework web part with Vue.js. Check out this code snippet: export default class MyWorkspaceTestWebPart extends BaseClientSideWebPart<IMyWorkspaceTestWebPartProps> { public uol_app; public render(): ...

Unable to display HTML content on a page using the foreach callback in JavaScript

I have a function that iterates through each element of an array and generates HTML content on the page while updating some properties using elements from the array. I am utilizing forEach to iterate over the elements of the array and innerHTML to display ...

Tips for dynamically sending data without explicitly stating the name:

Looking to create a JSON structure with name and value pairs such as name:"john". Check out the code snippet below: var allFields = []; var inputs = document.getElementsByTagName('input'); for(var i=0; i<inputs.length;i++){ name = in ...

Just a Quick Query About Regular Expressions

I need help removing a specific part from a URL string, which looks like this: http://.....?page=1. I am aware that the code "document.URL.replace("?page=[0-9]", "")" does not work, so I am curious to learn how to accomplish this task correctly. Thank you ...

Monitoring and recording Ajax requests, and retrying them if they were unsuccessful

As a newcomer to Javascript, I'm diving into the world of userscripts with the goal of tracking all Ajax calls within a specific website. My objective is to automatically repeat any failed requests that do not return a status code of 200. The catch? T ...

Tips for retrieving selected items in an array object

Within my UI, I have a select field that, on change, populates corresponding data in a div with nested ul and li elements. What I am attempting to achieve is to convert the selected items within the list (which include checkboxes) into an object of arrays ...

Looking for a smart way to extract all the selected elements from a form?

I am attempting to retrieve all the checked items from this form using JavaScript. I have looked at previous solutions, but none of them fit my requirements. <form id="checkform" class="container" style="margin-top:20px;"> <input type="checkb ...

I keep encountering a 404 error page not found whenever I try to use the useRouter function. What could

Once the form is submitted by the user, I want them to be redirected to a thank you page. However, when the backend logic is executed, it redirects me to a 404 page. I have checked the URL path and everything seems to be correct. The structure of my proje ...

Having trouble with React's conditional rendering not working as expected?

I am currently working on updating the contents of my Navbar and Router by using useContext and conditional rendering techniques. Here is a snippet from my App.js: import "./App.css"; import axios from "axios"; import { AuthContextProv ...

Using JWPlayer 6 and JWPlayer 7 simultaneously in one project - how is it done?

Trying to incorporate both JWPlayer 6 and JWPlayer 7 into my expressJS, AngularJS project has been a challenge. While they each work independently without issue, bringing them together has proven to be tricky. In my index.html file, I include them separat ...

Achieving synchronous function execution with a single click in React

In my current project, I am utilizing ReactJs and Redux. I have encountered a scenario where I need to trigger two functions sequentially with just one click on the mainfunc(). The second function should only execute after the first function has complete ...