Implementing Shader Effects around Mouse using Three.js

Could someone please share tips on how to add a shader effect around the mouse area using Three.js? I'm inspired by the homepage of this website:

I'm eager to explore some leads or examples. Thank you in advance!

Answer №1

Implementing a custom postprocessing shader to track mouse movements is a creative way to enhance your project.

Below is a basic example inspired by a blur postprocessing shader:

var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 1000);
camera.position.set(0, 0, 15);
var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

var controls = new THREE.OrbitControls(camera, renderer.domElement);

var cubes = [];

for (let i = 0; i < 500; i++) {
  let cube = new THREE.Mesh(new THREE.BoxGeometry(1, 1, 1), new THREE.MeshBasicMaterial({
    color: Math.random() * 0x777777 + 0x777777,
    wireframe: true
  }));
  cube.position.set(THREE.Math.randFloatSpread(10), THREE.Math.randFloatSpread(10), THREE.Math.randFloatSpread(10));
  scene.add(cube);
  cubes.push(cube);
}

var composer = new THREE.EffectComposer(renderer);
composer.addPass(new THREE.RenderPass(scene, camera));

var hblur = new THREE.ShaderPass(THREE.HorizontalBlurShader);
composer.addPass(hblur);

var vblur = new THREE.ShaderPass(THREE.VerticalBlurShader);
console.log(vblur);
vblur.renderToScreen = true;
composer.addPass(vblur);

var mouse = new THREE.Vector2();

window.addEventListener("mousemove", function(event) {
  mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
  mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
}, false)

render();

function render() {
  requestAnimationFrame(render);
  cubes.forEach((cube, index) => {
    cube.rotation.x += 0.0001 * index;
    cube.rotation.y += 0.0001 * index;
    cube.rotation.z += 0.0001 * index;
  });
  hblur.uniforms.mouse.value.copy(mouse);
  vblur.uniforms.mouse.value.copy(mouse);
  composer.render(scene, camera);
}
body {
  overflow: hidden;
  margin: 0;
}
<script src="https://threejs.org/build/three.min.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>

<script src="https://threejs.org/examples/js/shaders/CopyShader.js"></script>
<script>
  THREE.HorizontalBlurShader = {

    uniforms: {

      "tDiffuse": {
        value: null
      },
      "h": {
        value: 1.0 / 256.0
      },
      "mouse": {
        value: new THREE.Vector2()
      },
      "ratio": {
        value: window.innerWidth / window.innerHeight
      }
    },

    vertexShader: `
    varying vec2 vUv;
    
void main() {
vUv = uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
    }`,
    fragmentShader: `
uniform sampler2D tDiffuse;
uniform float h;
    uniform vec2 mouse;
    uniform float ratio;
varying vec2 vUv;

  void main() {
      vec2 uv = vUv;
      uv = -1. + 2. * uv;
      uv -= mouse;
      uv.x *= ratio;
      if ( length(uv) > 0.25 ) {
        gl_FragColor = texture2D(tDiffuse, vUv);
      } 
      else{

        vec4 sum = vec4( 0.0 );

        sum += texture2D( tDiffuse, vec2( vUv.x - 4.0 * h, vUv.y ) ) * 0.051;
        sum += texture2D( tDiffuse, vec2( vUv.x - 3.0 * h, vUv.y ) ) * 0.0918;
        sum += texture2D( tDiffuse, vec2( vUv.x - 2.0 * h, vUv.y ) ) * 0.12245;
        sum += texture2D( tDiffuse, vec2( vUv.x - 1.0 * h, vUv.y ) ) * 0.1531;
        sum += texture2D( tDiffuse, vec2( vUv.x, vUv.y ) ) * 0.1633;
        sum += texture2D( tDiffuse, vec2( vUv.x + 1.0 * h, vUv.y ) ) * 0.1531;
        sum += texture2D( tDiffuse, vec2( vUv.x + 2.0 * h, vUv.y ) ) * 0.12245;
        sum += texture2D( tDiffuse, vec2( vUv.x + 3.0 * h, vUv.y ) ) * 0.0918;
        sum += texture2D( tDiffuse, vec2( vUv.x + 4.0 * h, vUv.y ) ) * 0.051;

        gl_FragColor = sum;
      }

}`

  };
</script>
<script>
  THREE.VerticalBlurShader = {

    uniforms: {

      "tDiffuse": {
        value: null
      },
      "v": {
        value: 1.0 / 256.0
      },
      "mouse": {
        value: new THREE.Vector2()
      },
      "ratio": {
        value: window.innerWidth / window.innerHeight
      }

    },

    vertexShader: `
    varying vec2 vUv;
    
void main() {
vUv = uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
    }`,

    fragmentShader: `
uniform sampler2D tDiffuse;
uniform float v;
    uniform vec2 mouse;
    uniform float ratio;
varying vec2 vUv;

  void main() {
      vec2 uv = vUv;
      uv = -1. + 2. * uv;
      uv -= mouse;
      uv.x *= ratio;
      if ( length(uv) > 0.25 ) {
        gl_FragColor = texture2D(tDiffuse, vUv);
      } 
      else{
        vec4 sum = vec4( 0.0 );

        sum += texture2D( tDiffuse, vec2( vUv.x, vUv.y - 4.0 * v ) ) * 0.051;
        sum += texture2D( tDiffuse, vec2( vUv.x, vUv.y - 3.0 * v ) ) * 0.0918;
        sum += texture2D( tDiffuse, vec2( vUv.x, vUv.y - 2.0 * v ) ) * 0.12245;
        sum += texture2D( tDiffuse, vec2( vUv.x, vUv.y - 1.0 * v ) ) * 0.1531;
        sum += texture2D( tDiffuse, vec2( vUv.x, vUv.y ) ) * 0.1633;
        sum += texture2D( tDiffuse, vec2( vUv.x, vUv.y + 1.0 * v ) ) * 0.1531;
        sum += texture2D( tDiffuse, vec2( vUv.x, vUv.y + 2.0 * v ) ) * 0.12245;
        sum += texture2D( tDiffuse, vec2( vUv.x, vUv.y + 3.0 * v ) ) * 0.0918;
        sum += texture2D( tDiffuse, vec2( vUv.x, vUv.y + 4.0 * v ) ) * 0.051;

        gl_FragColor = sum;
      }

}`

  };
</script>

<script src="https://threejs.org/examples/js/postprocessing/EffectComposer.js"></script>
<script src="https://threejs.org/examples/js/postprocessing/RenderPass.js"></script>
<script src="https://threejs.org/examples/js/postprocessing/MaskPass.js"></script>
<script src="https://threejs.org/examples/js/postprocessing/ShaderPass.js"></script>

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

Adjust the CSS for the "a" tag's "title" attribute

I am using jquery.fancybox to create an image modal on my website. I have noticed that I can add a description using the title attribute. However, when the description is too long, the text is displayed on a single line and some of it disappears. How can ...

Error message encountered when deploying a Discord bot on Heroku: "SyntaxError: Unexpected token '??='"

I encountered an issue when trying to deploy a Discord bot that I created using Node.js on Heroku. The error message is as follows: 2021-11-05T00:00:10.334347+00:00 app[web.1]: > node . 2021-11-05T00:00:10.334348+00:00 app[web.1]: 2021-11-05T00:00:10.3 ...

What is the proper way to utilize BrowserRouter when child routes are connected to components?

I recently started learning React and decided to create a signup form following a tutorial on React Tutorial. However, the tutorial turned out to be outdated. I attempted to implement browser redirects for the signup, login, and home page links by defining ...

Replace particular letters within the text with designated spans

Suppose I have this specific HTML code snippet: <div class="answers"> He<b>y</b> <span class='doesntmatter'>eve</span>ryone </div> Additionally, imagine I possess the subsequent array: ['correct' ...

Disappearing input field in DateTimePicker Bootstrap when blurred

Currently, I am utilizing the Bootstrap DateTimePicker plugin to enable users to select a specific date and time. The plugin functions well with one minor issue - whenever the user clicks outside or loses focus on the calendar box, both the box itself and ...

Tips for creating a breakpoint in Sass specifically for a 414px iPhone screen size

For my latest project, I am utilizing sass and looking to incorporate a sass breakpoint or media query. My goal is to have the code execute only if the screen size is 414px or less. Below is my existing code: @include media-breakpoint-down(sm) { .sub-men ...

The canDeactivate function in the Angular 2 router can modify the router state even if I choose to cancel an action in the confirmation popup

In my Angular 2 project, I have implemented the canDeactivate method to prevent browser navigation. When a user tries to leave the page, a confirmation popup is displayed. However, if the user chooses to cancel, the router still changes its state even th ...

Stepper wizard experiences a variation in CSS styling when minified

Two plunkers showcasing material design wizard selectors are causing different behavior upon stepper clicks. One uses a minified version of CSS while the other is expanded. The issue arises with the transition effects in the .step-wizard .progressbar class ...

What is the best way to manage a vuex dispatch response?

Despite feeling like the answer is right in front of me, I'm waving the white flag and seeking suggestions. The challenge lies in my login form that submits to an AWS API and reacts to the result. The trouble starts when the handleSubmit method is tr ...

Unable to set options, such as the footer template, in Angular UI Typeahead

I am looking for a way to enhance the results page with a custom footer that includes pagination. I have noticed that there is an option to specify a footer template in the settings, but I am struggling to find examples of how to configure these options th ...

Issues with Autofocus in AngularJs on Firefox

Check out this straightforward directive to set autofocus: app.directive('autoFocus', function($timeout) { return { restrict: 'AC', link: function(_scope, _element) { $timeout(function(){ ...

An efficient JavaScript regular expression pattern that allows for both alphanumeric and special characters

Looking for a javascript regex that allows alphanumeric and special characters exclusively. The following regex was attempted but did not work: /^(?!.*(<|>)).*[a-zA-Z0-9 \\\\@!#$%^&*()_+-={}:;'\",.?|\[\&bs ...

The function queryDatabases is not supported in the DocumentDB JavaScript API

Currently, I am developing a service for Azure Functions using JavaScript/Node.js. However, I encounter an error when trying to access the function DocumentClient.queryDatabases. Despite having the correct references installed in Visual Studio Code and bei ...

Utilize the useRef hook in React to enable copying text to the clipboard

Looking to implement a copy to clipboard functionality in React using the useRef hook? Want to accomplish this without relying on any additional libraries? Take a look at my code snippet below. Currently, I'm encountering an error stating myRef.curren ...

What could be the reason behind the child component updating without triggering a re-render in Reactjs?

I am encountering an issue with my main component and child chart component. Even though the main component updates the state of the child chart component upon connecting to a websocket, the chart does not redraw as expected. Interestingly, when I click on ...

Exploring the concepts of AngularJS directives and resources

I've been experimenting with angularjs and rest service calls to display specific data sets, but I'm encountering challenges with custom directives and resources. Currently, I have a custom directive that loads a list of comments in an applicati ...

Encountering a glitch while trying to utilize History.js

I've decided to incorporate History.js into my web application to address the lack of support for history.pushState() in Internet Explorer. After reviewing various demos and tutorials, I have written this code snippet: var historyJs = window.History; ...

Controlling Javascript events

Currently, I am working on implementing an in-place editor using jQuery. The functionality is such that when you click on the text you wish to edit, it will replace the content with an input field, specifically a select tag. Everything seems to be functio ...

Exploring shader file content within three.js with the help of jQuery

I am trying to retrieve the content of a string that I have imported using HTML from within another script. To include the text file in question in the html file: <script src="shaders/fragmentshader.fs" id=fragmentshader></script> After impo ...

What is the best way to calculate the total of all files within a folder structure using JavaScript

Here is the array I'm working with: Array (7812) 0 {foldername: "", amount_of_files: 12, children: 86} 1 {foldername: "/pm", amount_of_files: 3, children: 7} 2 {foldername: "/pm/css", amount_of_files: 1, children: 0} 3 {f ...