Shader customization and dynamic window resizing with Three.js

Having trouble with resizing the Three.js shader scene using ThreeX to handle window resizing and changing orientation on mobile devices. When the window width is decreased, everything works perfectly. However, expanding the window either in width or height doesn't cause the scene to fill the new space. Also, resizing the window's height results in a failure, causing the mouse-location calculation to become dislocated from the actual mouse position. Need help troubleshooting where the mistake might be.

UPDATE: The issue can be replicated in JSFIDDLE. Click the link to activate the shader and resize the fiddle to observe the resizing problems.

Image 01: Window resized larger with shader not expanding accordingly

Image 02: Window with decreased height and misaligned mouse/mouse-coordinates (white dot represents mouse, color circle should align perfectly)

https://i.sstatic.net/RROtG.jpg https://i.sstatic.net/N43B4.jpg

<script>
        var scene;
        var camera;
        var renderer;

        function scene_setup(){

            scene = new THREE.Scene();
  scene.background = new THREE.Color( 0xffffff );
            var width = window.innerWidth;
            var height = window.innerHeight;

            camera = new THREE.OrthographicCamera( width / - 2, width / 2, height / 2, height / - 2, 1, 1000 );
            camera.position.z = 2;
 THREEx.WindowResize(renderer, camera);
            renderer = new THREE.WebGLRenderer();
            renderer.setSize( window.innerWidth, window.innerHeight );
            document.getElementById("curse").appendChild( renderer.domElement );

        }

        var bufferScene;
        var textureA;
        var textureB;
        var bufferMaterial;
        var plane;
        var bufferObject;
        var finalMaterial;
        var quad;

        function buffer_texture_setup(){

            bufferScene = new THREE.Scene();

            textureA = new THREE.WebGLRenderTarget( window.innerWidth, window.innerHeight, { minFilter: THREE.LinearFilter, magFilter: THREE.NearestFilter});
            textureB = new THREE.WebGLRenderTarget( window.innerWidth, window.innerHeight, { minFilter: THREE.LinearFilter, magFilter: THREE.NearestFilter} );

            bufferMaterial = new THREE.ShaderMaterial( {
                uniforms: {
                 bufferTexture: { type: "t", value: textureA },
                 res : {type: 'v2',value:new THREE.Vector2(window.innerWidth,window.innerHeight)},//Keeps the resolution
                 smokeSource: {type:"v3",value:new THREE.Vector3(0,0,0)},
                 time: {type:"f",value:Math.random()*Math.PI*2+Math.PI}
                },
                fragmentShader: document.getElementById( 'fragS' ).innerHTML
            } );
            plane = new THREE.PlaneBufferGeometry( window.innerWidth, window.innerHeight );
            bufferObject = new THREE.Mesh( plane, bufferMaterial );
            bufferScene.add(bufferObject);

            //Draw textureB to screen 
            finalMaterial =  new THREE.MeshBasicMaterial({map: textureB});
            quad = new THREE.Mesh( plane, finalMaterial );
            scene.add(quad);
        }


        scene_setup();


        buffer_texture_setup();




        var mouseDown = false;
        function UpdateMousePosition(X,Y){
            var mouseX = X;
            var mouseY = window.innerHeight - Y;
            bufferMaterial.uniforms.smokeSource.value.x = mouseX;
            bufferMaterial.uniforms.smokeSource.value.y = mouseY;
        }
        document.onmousemove = function(event){
            UpdateMousePosition(event.clientX,event.clientY)
        }

        document.onmousedown = function(event){
            mouseDown = true;
            bufferMaterial.uniforms.smokeSource.value.z = 0;
        }
        document.onmouseup = function(event){
            mouseDown = false;
            bufferMaterial.uniforms.smokeSource.value.z = 0.02;
        }

        function render() {

          requestAnimationFrame( render );


          renderer.render(bufferScene,camera,textureB,true);

          var t = textureA;
          textureA = textureB;
          textureB = t;
          quad.material.map = textureB;
          bufferMaterial.uniforms.bufferTexture.value = textureA;


          bufferMaterial.uniforms.time.value += 0.01;


          renderer.render( scene, camera );
        }
        render();

//shader

      </script>  
<script id="fragS">
        uniform vec2 res;//The width and height of our screen
        uniform sampler2D bufferTexture;//Our input texture
        uniform vec3 smokeSource;//The x,y are the posiiton. The z is the power/density
        uniform float time;
        void main() {
            vec2 pixel = gl_FragCoord.xy / res.xy;
            //Get the distance of the current pixel from the smoke source
            float dist = distance(smokeSource.xy,gl_FragCoord.xy);
            //Get the color of the current pixel
            gl_FragColor = texture2D( bufferTexture, pixel );

            //Generate smoke when mouse is pressed
            gl_FragColor.rgb += smokeSource.z * max(100.0-dist,0.02);


            //Smoke diffuse
            float xPixel = 1.0/res.x;//The size of a single pixel
            float yPixel = 4.0/res.y;
            vec4 rightColor = texture2D(bufferTexture,vec2(pixel.x+xPixel,pixel.y));
            vec4 leftColor = texture2D(bufferTexture,vec2(pixel.x-xPixel,pixel.y));
            vec4 upColor = texture2D(bufferTexture,vec2(pixel.x,pixel.y+yPixel));
            vec4 downColor = texture2D(bufferTexture,vec2(pixel.x,pixel.y-yPixel));
            //Handle the bottom boundary
            if(pixel.y <= yPixel){
                downColor.rgb = vec3(0.0);
            }
            //Diffuse equation
            float factor = 1.0 * 0.020 * (leftColor.r + rightColor.r + downColor.r * 3.0 + upColor.r - 6.0 * gl_FragColor.r);

            //Account for low precision of texels
            float minimum = 0.003;
            if(factor >= -minimum && factor < 0.0) factor = -minimum;

            gl_FragColor.rgb += factor;

         }
    </script>

Answer №1

Debugging would be much simpler if this were in a jsfiddle. The concept here involves creating a plane that matches the size of the screen, with each world unit representing one pixel.

plane = new THREE.PlaneBufferGeometry( window.innerWidth, window.innerHeight );

As the window size changes, the camera size also changes. So, you only need to do this once:

var width = window.innerWidth;
var height = window.innerHeight;

camera = new THREE.OrthographicCamera( width / - 2, width / 2, height / 2, height / - 2, 1, 1000 );

Subsequently, you can rely on a third-party tool to handle the changes in width and height. While these values change, your plane remains constant.

For drawing a full-screen quad, a simple solution could be:

new THREE.PlaneBufferGeometry(2,2,1,1)

Followed by the vertex shader:

void main(){
  gl_Posiiton = vec4(position.xy,0.,1.);
}

The same concept can be extended to the node graph:

new PlaneBufferGeometry(1,1,1,1)

onResize(){
   planeMesh.scale.set(width,height,1)
}

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

Updating the innerHTML of a button with a specific id using Javascript is not possible due to it being "null."

My objective is to create a button that, when clicked, triggers a function to alter the styling of the HTML tag as well as the text or innerHTML of the button itself. Sounds simple enough, right? Unfortunately... The HTML: <!DOCTYPE html> <html& ...

Attempting to recreate the dynamic banner featured in the video

Looking to replicate a setup similar to what was demonstrated in the video. I have two div blocks - one with a random image and the other with a video, and I want them to be as flexible and identical as possible to the video layout. How should I go about a ...

Testing if the App properly renders results in an error message: "No element found with the text: Profil"

I am struggling with testing Jest as I lack experience in this area. Specifically, I need to determine whether the App component is being rendered successfully. However, my test cases are failing. Upon checking the console log, I encountered the following ...

"Encountered a type error: The .join method is not recognized as a function

Hello everyone, I've encountered an issue that has me a bit stumped. I recently took over a project and found a problem in which the previous developer was attempting to join an array of strings. Unfortunately, when I try to build the project, I keep ...

What is the method to modify an action in an Ajax function?

I am trying to modify the action in the AjaxUpload function. The issue is that the value of setnamefile in the action does not change because the page does not reload. My idea was to change the action on submit, but I have not been able to do so successfu ...

Anticipate the occurrence of an event in Node.js

Is there a way to wait for an event in node js? In my bpmn workflow development, I need to execute the events step by step. Each script represents an event within the server that consists of multiple scripts. For example: 'use strict'; const Bpm ...

Exploring the Factory Design Pattern Together with Dependency Injection in Angular

I'm currently implementing the factory design pattern in Angular, but I feel like I might be missing something or perhaps there's a more efficient approach. My current setup involves a factory that returns a specific car class based on user input ...

Does the onchange function in the dropdown list only work when the first item is changed?

Here is a snippet of my HTML code featuring a list item generated from a database using a foreach loop: <select class="form-control select" id="inventoryitem" name="inventoryitem" onchange="getunit();"> <option>---Select an item---</o ...

Angular developers are struggling to find a suitable alternative for the deprecated "enter" function in the drag and drop CDK with versions 10 and above

By mistake, I was working on an older version of Angular in StackBlitz (a code-pane platform). I came across a function called enter on GitHub, but it didn't solve my issue. I was working on a grid-based drag and drop feature that allows dragging bet ...

Angular causing WKWebview to freeze

Situation Our Angular+Bootstrap app is functioning smoothly in Desktop on all operating systems, as well as Android and iPhone devices. There are no visible JavaScript errors or CSS warnings. Dilemma However, an issue arises intermittently while using t ...

IE is failing to trigger jAlert function

When I validate a text box by pressing the enter key on my keyboard, the validation works fine but the JAlert doesn't show up. However, when I call the same function on a button click, the alert shows in IE. I am quite confused by this behavior and wo ...

Typescript is throwing a Mongoose error stating that the Schema has not been registered for the model

I've dedicated a lot of time to researching online, but I can't seem to figure out what's missing in this case. Any help would be greatly appreciated! Permission.ts (This is the Permission model file. It has references with the Module model ...

The functionality of opening a new tab when clicking on a link image is not functioning correctly on Mozilla, whereas it

Check out my code below: <a target="_blank" href="#" onclick="window.open('https://www.google.com','_blank');"> <img src="#{request.contextPath}/resources/img/landing-page/terdaftar-kominfo.png" /> </a> ...

Is there a way to dynamically replace a section of a link with the current URL using JavaScript or jQuery?

I have a link that appears on multiple pages, and I want to dynamically change part of the link based on the current URL* of the page being visited. (*current URL refers to the web address shown in the browser's address bar) How can I use JavaScript ...

Storing executable scripts in HTML5 LocalStorage allows for the dynamic creation

As I work on a hybrid app with its own local HTML and JS files, there are times when I need to load additional small executable JS scripts and CSS from the server. Currently, I achieve this by using $.getScript, which has been working well. In order to ma ...

Raphael JS Path Animation: Wiping Away

I have successfully created a line animation using RaphaelJS, which can be viewed on this jsfiddle link - http://jsfiddle.net/7n040zdu/. My next challenge is to create an erasing animation that follows the initial one. This erasing animation should mimic t ...

Passing values to the next page is not functioning as expected

I'm having trouble passing a variable called userId to the next page in my application. Below is the snippet of code I am using to pass the value to the next page: $.each($.parseJSON(data), function(key, value) { var userId = value.id_user; ...

"Experience the latest version of DreamFactory - 2.0.4

I'm encountering a 404 error when I send a request to my new DSP. GET http://example.com/api/v2/sericename/_table/tablename 404 (Not Found) Upon checking the Apache error.log, I found this message: ... Got error: PHP message: REST Exception #404 &g ...

Tips for troubleshooting Node.js React Express applications

Having a background in traditional programming, I am used to putting breakpoints in code and having the debugger take me directly to the problematic section when executed. However, as I delve into web app development, it seems that debugging is limited to ...

"Error: The definition of the onclick function in jQuery is

I'm currently facing an issue with an ajax script in WordPress. I am attempting to post from a function using an onclick href, but it keeps showing up as undefined. I have tried rearranging the code both inside and outside of the scope, but I haven&ap ...