2
votes

I am implementing a Three.js shader and I have included ThreeX as a way to resize the scene when the window resizes, to deal with changing browser window size and changing orientation on mobile.

When the window width is made smaller it works like a charm; however, when the window is made bigger (either width or height) than when it first loaded the scene does not expand to fill the new space. Also, the resize fails completely when the height of the window is resized smaller. When the hight of the window is shrunk the calculated mouse-location does not change to a address new height and becomes dislocated from the actual mouse location. (see screenshots)

Help! Looking for where I have gone wrong.

UPDATE: Problem reproduced in JSFIDDLE Click to activate shader and resize fiddle to see resizing issues.

Image 01: Shows window resized larger and the shader not expanding to match

Image 02: Shows window with smaller resized height and mismatched mouse / mouse-coordinates (mouse is white dot and color circle should be right on it

Image 01 Image02

<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>
1
I don't see your shaders, nor your resize logic (what is threex?) but do you ever update your uniforms.res.value?pailhead
@pailhead the actual shader visuals are not the issue, so I left it out to not confuse the point. ThreeX is a single line of three.js code that tells the renderer and camera to resize with the window. not so sure what updating uniforms.res.value does for me in this context. if you wouldn't mind explaining…I would very much appreciate it!studiostudio
Without the shader it's really hard to tell what the shader is supposed to do :) I just noticed something called res and noticed that you do set window values on it. Those values change. When they change, do you update your res.value vector? If you can drop threex, or modify it, try adding another line to it, basically just bufferMaterial.uniforms.res.value.set(window.innerWidth,window.innerHeight)pailhead
To further clarify, the positioning of the image could be controlled by your vertex shader or by your fragment shader. Infinitely many permutations on how you got there. Based on this code i'm guessing the res may have something to do with it, with the shader i would be able to tell you exactly what is going on.pailhead
i would also swap out these gradients and blending if you have it with just red blue etc. to have a clearer picture of what goes on, where geometry ends etc etc.pailhead

1 Answers

0
votes

If this were in a jsfiddle it would be easier to debug. You create a world size plane, and match the world size with your screen size. Ie 1 world unit represents one pixel.

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

When the window size changes, your camera size changes as well. Ie. you call this once:

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

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

And then you let your 3rd party thing manage it. When that happens these width values for example change. Your plane stays the same.

A simple fix for drawing a full screen quad could perhaps be done like so:

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

And then vertex shader

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

Otherwise the same idea applies to the node graph:

new PlaneBufferGeometry(1,1,1,1)

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