使用gluUnproject将2d像素坐标转换为3d世界坐标

时间:2016-11-28 21:48:35

标签: webgl translation

rows<-500
cols<-4004
dat2 <- array(as.matrix(dataGaus[[1]]), dim=c(rows, 4, cols/4))
dat3 <- as.data.frame(matrix(aperm(dat2, c(1, 3, 2)), rows*cols/4, 4))
var canvas;
var gl;
var shaderProgram;
var triangleVertexPositionBuffer;
var mvMatrix = mat4.create();
var mOrtho = mat4.create();
var width;
var height;

function start()
{
  canvas = document.getElementById("glcanvas");
  canvas.addEventListener("mousedown", getPosition, false);
  width = canvas.width;
  height = canvas.height;
  initWebGL(canvas);

  if (gl) {
    initShaders();
    initBuffers();
    setInterval( drawScene, 15 );
  }
}

function drawScene() {

  gl.viewport(0,0,gl.viewportWidth, gl.viewportHeight);

  gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

  mat4.ortho(mOrtho, -gl.viewportWidth, gl.viewportWidth, -gl.viewportHeight, gl.viewportHeight, 0, -200);

  mat4.identity(mvMatrix);

  setMatrixUniforms();

  gl.bindBuffer(gl.ARRAY_BUFFER, triangleVertexPositionBuffer);

  gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, triangleVertexPositionBuffer.itemSize, gl.FLOAT, false, 0, 0);

  gl.drawArrays(gl.TRIANGLES, 0, triangleVertexPositionBuffer.numItems);


}

function setMatrixUniforms() {
  gl.uniformMatrix4fv(shaderProgram.mvMatrixUniform, false, mOrtho);
}

function initBuffers()
{
  triangleVertexPositionBuffer = gl.createBuffer();

  gl.bindBuffer(gl.ARRAY_BUFFER, triangleVertexPositionBuffer);

  var vertices = [
    0.0,  0.0,  0.0,
    50.0, 50.0,  0.0,
    50.0,   0.0,  0.0
  ];

  gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);

  triangleVertexPositionBuffer.itemSize = 3;

  triangleVertexPositionBuffer.numItems = 3;
}

function initShaders()
{
  var fragmentShader = getShader(gl, "shader-fs");

  var vertexShader = getShader(gl, "shader-vs");

  shaderProgram = gl.createProgram();

  gl.attachShader(shaderProgram, vertexShader);

  gl.attachShader(shaderProgram, fragmentShader);

  gl.linkProgram(shaderProgram);  

  if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {

    alert("Unable to initialize the shader program: " + gl.getProgramInfoLog(shader));

  }	

  gl.useProgram(shaderProgram);

  shaderProgram.vertexPositionAttribute = gl.getAttribLocation(shaderProgram, "aVertexPosition");

  gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute);

  shaderProgram.mvMatrixUniform = gl.getUniformLocation(shaderProgram, "uMVMatrix");
}

function initWebGL() {

  gl = null;

  try {

    gl = canvas.getContext("experimental-webgl");

    gl.viewportHeight = canvas.height;

    gl.viewportWidth = canvas.width;

  }

  catch(e) {

  }

  if (!gl) {

    alert("Unable to initialize WebGL. Your browser may not support it.");

  }
}

function getPosition(event)
{
  var x = event.clientX;
  var y = event.clientY;

  var viewportArray = [
    0, 0, 700, 700
  ];

  var modelPointArrayResults = [];

  var success = GLU.unProject(
    x, y, 0,
    mvMatrix, mOrtho,
    viewportArray, modelPointArrayResults);

  alert("x:" + modelPointArrayResults[0] + " y:" + modelPointArrayResults[1]);
} 

function getShader(gl, id) {

  var shaderScript = document.getElementById(id);

  if (!shaderScript) {
    return null;
  }

  var theSource = "";

  var currentChild = shaderScript.firstChild;

  while(currentChild) {

    if (currentChild.nodeType == 3) {

      theSource += currentChild.textContent;

    }

    currentChild = currentChild.nextSibling;

  }

  var shader;

  if (shaderScript.type == "x-shader/x-fragment") {

    shader = gl.createShader(gl.FRAGMENT_SHADER);

  } else if (shaderScript.type == "x-shader/x-vertex") {

    shader = gl.createShader(gl.VERTEX_SHADER);

  } else {

    return null;  // Unknown shader type

  }

  gl.shaderSource(shader, theSource);

  gl.compileShader(shader);

  if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {

    alert("An error occurred compiling the shaders: " + gl.getShaderInfoLog(shader));

    return null;

  }

  return shader;

}	

/*jslint white: false, onevar: false, undef: true, nomen: true, eqeqeq: true, plusplus: true, bitwise: true, regexp: true, newcap: true, immed: true, sub: true, nomen: false */

/**
 * This file contains code that may be under the following license:
 *
 * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
 * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
 *
 * See http://oss.sgi.com/projects/FreeB/ for more information.
 *
 * All code in this file which is NOT under the SGI FREE SOFTWARE LICENSE B
 * is free and unencumbered software released into the public domain.
 *
 * Anyone is free to copy, modify, publish, use, compile, sell, or
 * distribute this software, either in source code form or as a compiled
 * binary, for any purpose, commercial or non-commercial, and by any
 * means.
 *
 * In jurisdictions that recognize copyright laws, the author or authors
 * of this software dedicate any and all copyright interest in the
 * software to the public domain. We make this dedication for the benefit
 * of the public at large and to the detriment of our heirs and
 * successors. We intend this dedication to be an overt act of
 * relinquishment in perpetuity of all present and future rights to this
 * software under copyright law.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 */

/** @type {Object} */
var GLU = {};

(function($) {
  /**
     * Unproject a screen point.
     *
     * @param {number} winX the window point for the x value.
     * @param {number} winY the window point for the y value.
     * @param {number} winZ the window point for the z value.
     * @param {Array.<number>} model the model-view matrix.
     * @param {Array.<number>} proj the projection matrix.
     * @param {Array.<number>} view the viewport coordinate array.
     * @param {Array.<number>} objPos the model point result.
     * @return {boolean} true if the unproject operation was successful, false otherwise.
     */
  $.unProject = function(winX, winY, winZ, model, proj, view, objPos) {

    /** @type {Array.<number>} */
    var inp = [
      winX,
      winY,
      winZ,
      1.0
    ];

    /** @type {Array.<number>} */
    var finalMatrix = [];

    $.multMatrices(model, proj, finalMatrix);
    if (!$.invertMatrix(finalMatrix, finalMatrix)) {
      return (false);
    }

    /* Map x and y from window coordinates */
    inp[0] = (inp[0] - view[0]) / view[2];
    inp[1] = (inp[1] - view[1]) / view[3];

    /* Map to range -1 to 1 */
    inp[0] = inp[0] * 2 - 1;
    inp[1] = inp[1] * 2 - 1;
    inp[2] = inp[2] * 2 - 1;

    /** @type {Array.<number>} */
    var out = [];

    $.multMatrixVec(finalMatrix, inp, out);

    if (out[3] === 0.0) {
      return false;
    }

    out[0] /= out[3];
    out[1] /= out[3];
    out[2] /= out[3];

    objPos[0] = out[0];
    objPos[1] = out[1];
    objPos[2] = out[2];

    return true;
  };

  /**
     * Multiply the matrix by the specified vector.
     *
     * @param {Array.<number>} matrix the matrix.
     * @param {Array.<number>} inp the vector.
     * @param {Array.<number>} out the output.
     */
  $.multMatrixVec = function(matrix, inp, out) {
    for (var i = 0; i < 4; i = i + 1) {
      out[i] =
        inp[0] * matrix[0 * 4 + i] +
        inp[1] * matrix[1 * 4 + i] +
        inp[2] * matrix[2 * 4 + i] +
        inp[3] * matrix[3 * 4 + i];
    }
  };

  /**
     * Multiply the specified matrices.
     *
     * @param {Array.<number>} a the first matrix.
     * @param {Array.<number>} b the second matrix.
     * @param {Array.<number>} r the result.
     */
  $.multMatrices = function(a, b, r) {
    for (var i = 0; i < 4; i = i + 1) {
      for (var j = 0; j < 4; j = j + 1) {
        r[i * 4 + j] =
          a[i * 4 + 0] * b[0 * 4 + j] +
          a[i * 4 + 1] * b[1 * 4 + j] +
          a[i * 4 + 2] * b[2 * 4 + j] +
          a[i * 4 + 3] * b[3 * 4 + j];
      }
    }
  };

  /**
     * Invert a matrix.
     *
     * @param {Array.<number>} m the matrix.
     * @param {Array.<number>} invOut the inverted output.
     * @return {boolean} true if successful, false otherwise.
     */
  $.invertMatrix = function(m, invOut) {
    /** @type {Array.<number>} */
    var inv = [];

    inv[0] = m[5] * m[10] * m[15] - m[5] * m[11] * m[14] - m[9] * m[6] * m[15] +
      m[9] * m[7] * m[14] + m[13] * m[6] * m[11] - m[13] * m[7] * m[10];
    inv[4] = -m[4] * m[10] * m[15] + m[4] * m[11] * m[14] + m[8] * m[6] * m[15] -
      m[8] * m[7] * m[14] - m[12] * m[6] * m[11] + m[12] * m[7] * m[10];
    inv[8] = m[4] * m[9] * m[15] - m[4] * m[11] * m[13] - m[8] * m[5] * m[15] +
      m[8] * m[7] * m[13] + m[12] * m[5] * m[11] - m[12] * m[7] * m[9];
    inv[12] = -m[4] * m[9] * m[14] + m[4] * m[10] * m[13] + m[8] * m[5] * m[14] -
      m[8] * m[6] * m[13] - m[12] * m[5] * m[10] + m[12] * m[6] * m[9];
    inv[1] = -m[1] * m[10] * m[15] + m[1] * m[11] * m[14] + m[9] * m[2] * m[15] -
      m[9] * m[3] * m[14] - m[13] * m[2] * m[11] + m[13] * m[3] * m[10];
    inv[5] = m[0] * m[10] * m[15] - m[0] * m[11] * m[14] - m[8] * m[2] * m[15] +
      m[8] * m[3] * m[14] + m[12] * m[2] * m[11] - m[12] * m[3] * m[10];
    inv[9] = -m[0] * m[9] * m[15] + m[0] * m[11] * m[13] + m[8] * m[1] * m[15] -
      m[8] * m[3] * m[13] - m[12] * m[1] * m[11] + m[12] * m[3] * m[9];
    inv[13] = m[0] * m[9] * m[14] - m[0] * m[10] * m[13] - m[8] * m[1] * m[14] +
      m[8] * m[2] * m[13] + m[12] * m[1] * m[10] - m[12] * m[2] * m[9];
    inv[2] = m[1] * m[6] * m[15] - m[1] * m[7] * m[14] - m[5] * m[2] * m[15] +
      m[5] * m[3] * m[14] + m[13] * m[2] * m[7] - m[13] * m[3] * m[6];
    inv[6] = -m[0] * m[6] * m[15] + m[0] * m[7] * m[14] + m[4] * m[2] * m[15] -
      m[4] * m[3] * m[14] - m[12] * m[2] * m[7] + m[12] * m[3] * m[6];
    inv[10] = m[0] * m[5] * m[15] - m[0] * m[7] * m[13] - m[4] * m[1] * m[15] +
      m[4] * m[3] * m[13] + m[12] * m[1] * m[7] - m[12] * m[3] * m[5];
    inv[14] = -m[0] * m[5] * m[14] + m[0] * m[6] * m[13] + m[4] * m[1] * m[14] -
      m[4] * m[2] * m[13] - m[12] * m[1] * m[6] + m[12] * m[2] * m[5];
    inv[3] = -m[1] * m[6] * m[11] + m[1] * m[7] * m[10] + m[5] * m[2] * m[11] -
      m[5] * m[3] * m[10] - m[9] * m[2] * m[7] + m[9] * m[3] * m[6];
    inv[7] = m[0] * m[6] * m[11] - m[0] * m[7] * m[10] - m[4] * m[2] * m[11] +
      m[4] * m[3] * m[10] + m[8] * m[2] * m[7] - m[8] * m[3] * m[6];
    inv[11] = -m[0] * m[5] * m[11] + m[0] * m[7] * m[9] + m[4] * m[1] * m[11] -
      m[4] * m[3] * m[9] - m[8] * m[1] * m[7] + m[8] * m[3] * m[5];
    inv[15] = m[0] * m[5] * m[10] - m[0] * m[6] * m[9] - m[4] * m[1] * m[10] +
      m[4] * m[2] * m[9] + m[8] * m[1] * m[6] - m[8] * m[2] * m[5];

    /** @type {number} */
    var det = m[0] * inv[0] + m[1] * inv[4] + m[2] * inv[8] + m[3] * inv[12];

    if (det === 0) {
      return false;
    }

    det = 1.0 / det;

    for (var i = 0; i < 16; i = i + 1) {
      invOut[i] = inv[i] * det;
    }

    return true;
  };

}(GLU));

/* EOF */

start();
#glcanvas { width: 700px; height: 700px; background-color: black; margin: 0px; padding: 0px; }

库: https://github.com/bringhurst/webgl-unproject

我已经设置了一个例子

  1. 当值应为正值时,y值将作为负值

  2. 并且转换后的坐标空间看起来像300平方单位,而不是700平方单位。

  3. 也出于某种原因

    1. X和Y似乎偏移了一点我不确定这是否与画布边界矩形有关。有谁知道如何解决这些问题?
    2. 我的矩阵库是glMatrix的最新CDN。想法是单击画布并弹出警报。

      谢谢!

      <script src="https://cdnjs.cloudflare.com/ajax/libs/gl-matrix/2.3.2/gl-matrix.js"></script>
      
      <script id="shader-fs" type="x-shader/x-fragment">
      		precision mediump float;
      
      		void main(void) {
      			gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
      		}
      </script>
      <script id="shader-vs" type="x-shader/x-vertex">
      		attribute vec3 aVertexPosition;
      
      		uniform mat4 uMVMatrix;
      
      		void main(void) {
      			gl_Position = uMVMatrix * vec4(aVertexPosition, 1.0);
      		}
      </script>
      <canvas id="glcanvas" />

1 个答案:

答案 0 :(得分:3)

  

1)当y值应该为a时,y值将作为负值   正值

在openGL中,[-1,-1]位于视口的左下角,右上角为[1,1]。 Y坐标增加“向上”。 具体来说,gluUnProject期望y = 0成为画布的底部。 https://github.com/bringhurst/webgl-unproject/blob/master/GLU.js#L76

  

2)并且坐标空间看起来像是300平方单位   转换不是像700平方单位那样的东西应该是。

您只需设置画布css大小。画布的css大小与宽度和高度属性之间没有关系。

css大小仅用于“拉伸”并将画布显示为给定大小(如img)。 宽度和高度设置画布的实际像素分辨率。

由于未设置,因此默认大小为300x150。它是用于设置otho矩阵的值,因此是取消项目时得到的结果。

  3)X和Y似乎被移动了一点点我不确定   如果这与画布边界矩形有关。有人知道吗   如何解决这些问题?

您使用鼠标事件的clientX和clientY作为unproject的输入。它是相对于浏览器屏幕的鼠标坐标。您需要提供相对于画布的坐标。转变来自默认的html边距