Three.js шейдер и изменение размера окна - PullRequest
0 голосов
/ 25 сентября 2018

Я реализую шейдер Three.js и включил ThreeX как способ изменения размера сцены при изменении размера окна, чтобы иметь дело с изменением размера окна браузера и изменением ориентации на мобильном телефоне.

Когда ширина окна уменьшается, он работает как шарм;однако, когда окно становится больше (либо ширины, либо высоты), чем при первой загрузке, сцена не расширяется, чтобы заполнить новое пространство.Кроме того, изменение размера завершается неудачей, когда высота окна уменьшается.Когда высота окна уменьшается, вычисленное местоположение мыши не изменяется на новую высоту адреса и становится смещенным от фактического положения мыши.(см. скриншоты)

Помогите!Ищите, где я ошибся.

ОБНОВЛЕНИЕ: проблема воспроизведена в JSFIDDLE Нажмите, чтобы активировать шейдер и изменить размер скрипта, чтобы увидеть проблемы с изменением размера.

Изображение 01: Изменение размера окна показабольше, а шейдер не расширяется, чтобы соответствовать

Изображение 02: Показывает окно с меньшей измененной высотой и несовпадающими координатами мыши / мыши (мышь - белая точка, и на ней должна быть цветная окружность

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();

// шейдер

      </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 Ответ

0 голосов
/ 26 сентября 2018

Если бы это было в jsfiddle, было бы легче отлаживать.Вы создаете плоскость мирового размера и сопоставляете размер мира с размером экрана.Т.е. 1 мировая единица представляет один пиксель.

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

При изменении размера окна изменяется и размер вашей камеры.То есть.Вы называете это один раз:

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

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

И затем вы позволяете сторонним вещам управлять этим.Когда это происходит, эти width значения, например, меняются.Ваш самолет остаётся прежним.

Простое исправление для рисования полноэкранного четырехугольника может быть сделано следующим образом:

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

А затем вершинный шейдер

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

В противном случае та же идея применима к графу узлов:

new PlaneBufferGeometry(1,1,1,1)

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