【问题标题】:Fragment shader position changes when browser zoomed浏览器缩放时片段着色器位置发生变化
【发布时间】:2016-07-16 02:24:38
【问题描述】:

我正在使用cocos2d-js webgl模式创建一个非常简单的shader效果:

用给定的中心位置和半径绘制一个实心圆。

片段着色器:

uniform vec2 position;
uniform vec3 lightColor;
uniform float lightSize;

    void main()
    {
        float distance = distance(gl_FragCoord.xy, position);
        if (distance <= lightSize) {
            gl_FragColor = vec4(lightColor, 1.0);
        }
        else {
            gl_FragColor = vec4(lightColor, 0.0);   
        }
    }

当浏览器未缩放 (100 %) 时,此代码可以正常工作。

但是,当我尝试将浏览器缩放到 80% 或 120% 时,我发现绘制的圆圈偏离了我设置的中心位置。

我不确定如何解决此问题,以确保无论我如何缩放浏览器,圆圈始终位于我设置的中心位置。

任何建议将不胜感激,谢谢:)

【问题讨论】:

  • 你为position设置了什么值?这是统一的,发布的代码没有显示您将其设置为什么值。

标签: javascript webgl shader cocos2d-js


【解决方案1】:

如果您的窗口是 (200, 200),那么中心是 (100, 100)。但是如果你的窗口突然变成 (400, 400),(100, 100) 就不再是中心了,对吧?这就是“窗口空间”的意思:相对于窗口的空间。

如果您想在不依赖于窗口属性的空间中进行计算,则必须将gl_FragCoord 转换为该空间。当然,您的position 也必须在同一个空间中。

一个常见的解决方案是获取窗口的大小并将其作为制服传递。然后将gl_FragCoord.xy 除以该大小。该空间中窗口的中心始终为 (0.5, 0.5)。但是您必须确保每当窗口改变尺寸时更新这个统一的。

【讨论】:

    【解决方案2】:

    在下面尝试您的着色器,我没有发现任何问题

    var fs = `
    precision mediump float;
    uniform vec2 position;
    uniform vec3 lightColor;
    uniform float lightSize;
    
        void main()
        {
            float distance = distance(gl_FragCoord.xy, position);
            if (distance <= lightSize) {
                gl_FragColor = vec4(lightColor, 1.0);
            }
            else {
                gl_FragColor = vec4(lightColor, 0.0);   
            }
        }
    `;
    var vs = `
    attribute vec4 a_position;
    void main() {
      gl_Position = a_position;
    }
    `;
    
    var gl = document.querySelector("canvas").getContext("webgl");
    var programInfo = twgl.createProgramInfo(gl, [vs, fs]);
    var bufferInfo = twgl.createBufferInfoFromArrays(gl, {
      a_position: { 
        numComponents: 2,
        data: [
          -1, -1,
          -1,  1,
           1, -1,
           1, -1,
          -1,  1,
           1,  1,
        ],
      },
    });
    
    function render(time) {
      time *= 0.001;
      twgl.resizeCanvasToDisplaySize(gl.canvas);
      gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
    
      var uniforms = {
        position: [gl.canvas.width / 2, gl.canvas.height / 2],
        lightColor: [0.5 + Math.sin(time * 10) * 0.25, 0, 0],
        lightSize: 100,
      };    
          
      gl.useProgram(programInfo.program);
      twgl.setBuffersAndAttributes(gl, programInfo, bufferInfo);
      twgl.setUniforms(programInfo, uniforms);
      twgl.drawBufferInfo(gl, gl.TRIANGLES, bufferInfo);
      requestAnimationFrame(render);
    }
    requestAnimationFrame(render);
          
    body { margin: 0; }
    canvas { display: block; width: 100vw; height: 100vh; }
    <script src="https://twgljs.org/dist/twgl.min.js"></script>
    <canvas></canvas>

    您将位置设置为什么?上面的代码将其设置为画布中间的gl.canvas.width / 2, gl.canvas.height / 2

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-03-04
      • 2017-10-05
      • 1970-01-01
      • 2011-09-19
      相关资源
      最近更新 更多