【问题标题】:Three.js shader and window resizeThree.js 着色器和窗口调整大小
【发布时间】:2019-03-01 09:39:31
【问题描述】:

我正在实现 Three.js 着色器,并且我已经将 ThreeX 作为一种在窗口调整大小时调整场景大小的方法,以处理更改浏览器窗口大小和更改移动设备上的方向。

当窗口宽度变小时,它就像一个魅力;但是,当窗口比首次加载时更大(宽度或高度)时,场景不会扩展以填充新空间。此外,当窗口的高度调整为较小时,调整大小完全失败。当窗口的高度缩小时,计算的鼠标位置不会更改为地址新高度,并且会与实际鼠标位置脱位。 (见截图)

帮助!寻找我哪里出错了。

更新:JSFIDDLE 中重现的问题单击以激活着色器并调整小提琴大小以查看调整大小问题。

图片 01:显示窗口大小调整后,着色器未扩展以匹配

图片 02:显示调整后高度较小且鼠标/鼠标坐标不匹配的窗口(鼠标为白点,色环应在其上

<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>

【问题讨论】:

  • 我没有看到你的着色器,也没有你的调整大小逻辑(什么是三倍?)但是你有没有更新你的uniforms.res.value
  • @pailhead 实际的着色器视觉效果不是问题,所以我省略了它以免混淆这一点。 ThreeX 是一行 three.js 代码,它告诉渲染器和相机随窗口调整大小。不太确定在这种情况下更新 uniforms.res.value 对我有什么作用。如果您不介意解释……我将不胜感激!
  • 如果没有着色器,很难判断着色器应该做什么 :) 我刚刚注意到一个名为 res 的东西,并注意到您确实在其上设置了窗口值。这些值会发生变化。当它们发生变化时,您是否更新您的res.value 向量?如果你可以删除三倍,或者修改它,尝试添加另一行,基本上只是bufferMaterial.uniforms.res.value.set(window.innerWidth,window.innerHeight)
  • 为了进一步说明,图像的位置可以由您的顶点着色器或片段着色器控制。关于你是如何到达那里的,有无数种排列。根据这段代码,我猜res 可能与它有关,使用着色器我可以准确地告诉你发生了什么。
  • 如果你只有红蓝等,我也会换掉这些渐变和混合,以便更清楚地了解发生了什么,几何结束等。

标签: javascript three.js window-resize


【解决方案1】:

如果这是在一个 jsfiddle 中,它会更容易调试。您创建一个世界大小的平面,并将世界大小与您的屏幕大小相匹配。即 1 个世界单位代表一个像素。

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

当窗口大小发生变化时,您的相机大小也会发生变化。 IE。你调用一次:

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

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

然后你让你的第 3 方来管理它。例如,当这种情况发生时,这些 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)
}

【讨论】:

  • 我想我遵循了 - 但不太确定实施 - 对此我深表歉意。这是jfiddle。介意看看吗?点击激活着色器
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-04-17
  • 2021-01-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-05-20
  • 1970-01-01
相关资源
最近更新 更多