如何在模型视图转换后获取正在绘制的对象的二维尺寸以在 webgl 上进行命中测试

2023-12-19

我遵循 webgl 基础知识并绘制 2d 对象并使用矩阵来缩放顶点和渲染。

在渲染之前我通过width/height设置为渲染四边形的顶点。这定义了对象的大小。但在顶点着色器中,我对这些顶点应用变换,如下所示:

in vec2 aPosition;
in vec2 aTexCoord;

out vec2 vQuadCoord;

uniform mat3 uMatrix;

void main() {

  vec2 position = (uMatrix * vec3(aPosition, 1)).xy;

  vQuadCoord = aTexCoord;

  gl_Position = vec4(position, 0, 1);

}

该矩阵控制translate/rotate/scale的对象。渲染后,我想知道这个对象的边界。但尤其是在缩放之后我无法知道界限。如果我将这个对象(带有矩阵)翻译为x,y它的位置是已知的,但如果我缩放这个对象,x 就会向左移动,移动量未知。 webgl 基础知识没有提到这个主题,什么是检测对象边界并精确转换的好方法,因为我也有枢轴问题,我可能会问另一个问题。


您需要将鼠标坐标转换为剪辑空间,然后将它们乘以矩阵的逆。这将为您提供相对于值的鼠标坐标aPosition.

之后就由你决定了。如果值(顶点)馈送到aPosition是一个矩形,您可以仅根据该矩形检查变换后的点。如果它们是像星星这样更复杂的形状,那么你需要创建自己的函数来完成point in star or point in triangle并检查每个三角形,但至少在变换之后,鼠标位置处于相对于顶点的坐标中。您还可以在初始化时计算顶点的边界框,并使用它来测试变换后的点。

function main() {
  const gl = document.querySelector('canvas').getContext('webgl2');
  if (!gl) {
    return alert('need WebGL2');
  }
  
  const vs = `#version 300 es
in vec2 aPosition;

uniform mat3 uMatrix;

void main() {

  vec2 position = (uMatrix * vec3(aPosition, 1)).xy;

  gl_Position = vec4(position, 0, 1);

}
  `;
  const fs = `#version 300 es
  precision mediump float;
  uniform vec4 color;
  out vec4 outColor;
  void main() {
    outColor = color;
  }

  `;
  
  const programInfo = twgl.createProgramInfo(gl, [vs, fs]);
  
  // create a quad that starts at 0,0 and is 20 units wide and 10 tall
  const bufferInfo = twgl.createBufferInfoFromArrays(gl, {
    aPosition: {
      numComponents: 2,
      data: [
        0, 0,
        0, 10,
        20, 0,
        
        20, 0,
        0, 10,
        20, 10,
      ],
    }
  });
  const vao = twgl.createVAOFromBufferInfo(gl, programInfo, bufferInfo);
  
  let mouseClipX = 0;
  let mouseClipY = 0;
  const infoElem = document.querySelector('#info');
  
  function render(time) {
    t = time / 1000;
    
    twgl.resizeCanvasToDisplaySize(gl.canvas);
    gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
    
    gl.useProgram(programInfo.program);
    gl.bindVertexArray(vao);
    
    let mat = m3.projection(gl.canvas.width, gl.canvas.height);
    
    mat = m3.translate(
       mat, 
       150 + Math.sin(t * 0.1) * 100,
       75 + Math.cos(t * 0.2) * 50);
    mat = m3.rotate(mat, t * 0.3);
    mat = m3.scale(
       mat, 
       2 + Math.sin(t * 0.4) * 0.5,
       2 + Math.cos(t * 0.5) * 0.5);
       
       
    // convert clipspace mouse to aPosition relative values
    // 'mat' takes aPosition and converts to clip space
    // so the inverse of 'mat' would take clip space and
    // convert back to aPosition space.
    const invMat = m3.inverse(mat);
    const p = m3.transformPoint(invMat, [mouseClipX, mouseClipY]);
    
    // now check in aPosition space. It's a 20x10 rect starting at 0,0 so
    const inbox = p[0] >= 0 && p[0] < 20 &&
                  p[1] >= 0 && p[1] < 10;
       
    
    twgl.setUniforms(programInfo, {
      uMatrix: mat,
      color: inbox ? [1, 0, 0, 1] : [0, 0, 1, 1],
    });
    twgl.drawBufferInfo(gl, bufferInfo);
        
    infoElem.textContent = inbox ? 'mouse in rect' : 'no hit';
    
    requestAnimationFrame(render);    
  }
  requestAnimationFrame(render);
  
  gl.canvas.addEventListener('mousemove', (event) => {
    // convert canvas relative mouse coordinates to clip space
    mouseClipX = (event.offsetX / gl.canvas.clientWidth ) *  2 - 1;
    mouseClipY = (event.offsetY / gl.canvas.clientHeight) * -2 + 1;  // note we flip Y
  });
}


main();
canvas { border: 1px solid black; }
<script src="https://twgljs.org/dist/4.x/twgl-full.min.js"></script>
<script src="https://webgl2fundamentals.org/webgl/resources/m3.js"></script>
<canvas></canvas>
<pre id="info"></pre>
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何在模型视图转换后获取正在绘制的对象的二维尺寸以在 webgl 上进行命中测试 的相关文章