WebGL: координаты холста в трехмерные координаты - PullRequest
3 голосов
/ 24 января 2012

Я пытаюсь найти «левую» границу моего порта просмотра WebGL, потому что я хотел бы нарисовать там отладочную информацию. (мини-карта оси, как у большинства программ моделирования) Я, конечно, могу получить ширину и высоту холста, содержащего окно просмотра WebGL.

Мне бы очень хотелось узнать, как бы я рассчитал вычисление координат 2D холста по координатам 3D? Как лучше всего найти левую границу в 3D-окне?


Любой, кто изучает это, должен прочитать http://webglfactory.blogspot.com/2011/05/how-to-convert-world-to-screen.html или взгляните на GluProject () и GluUnproject ()

Ответы [ 4 ]

6 голосов
/ 24 января 2012

Чтобы прояснить ответ datenwolf, отображение координат между вашим 3D-пространством и 2D-холстом - это именно то, что вы хотите.Вы управляете им с помощью gl.viewport и матриц, которые вы передаете своему шейдеру.

gl.viewport просто блокирует прямоугольник пикселей на холсте, на который вы рисуете.В большинстве случаев это точно соответствует размерам вашего холста, но есть некоторые сценарии, в которых вы хотите рисовать только его часть.(Например, игры с разделенным экраном.) С этого момента область холста, на которую вы рисуете, будет называться областью просмотра.Вы можете предположить, что это означает то же самое, что и «холст», если хотите.

В самом простом виде окно просмотра всегда имеет неявную систему координат от -1 до 1 по осям X и Y.Это пространство, в котором работает вывод gl_Position вашего вершинного шейдера. Если вы выводите вершину в точке (-1, -1), она будет в левом нижнем углу окна просмотра.вершина в (1, 1) будет в правом верхнем углу.(Да, сейчас я игнорирую глубину.) Используя это, вы можете создать геометрию, предназначенную для отображения в этом пространстве и нарисовать ее без каких-либо матричных преобразований, но это может быть немного неудобно.

Чтобы сделатьжизнь проще, мы используем проекционные матрицы.Матрица проекции - это просто матрица, которая преобразует вашу геометрию из некоторого произвольного трехмерного пространства в пространство от -1 до 1, требуемое для области просмотра.Наиболее распространенной является перспективная матрица.То, как вы его создадите, будет выглядеть по-разному в зависимости от используемой вами библиотеки, но обычно это что-то вроде этого:

var fov = 45;
var aspectRatio = canvas.width/canvas.height;
var near = 1.0;
var far = 1024.0;
var projectionMat = mat4.perspective(fov, aspect, near, far);

Я не собираюсь вдаваться в то, что означают все эти значения, но вы можете четковидим, что мы используем ширину и высоту холста, чтобы помочь настроить эту проекцию.Это позволяет ему не выглядеть растянутым или сжатым в зависимости от размера холста.Однако все сводится к тому, что, взяв любую трехмерную точку в пространстве и умножив ее на эту матрицу, вы получите точку, которая отображается в это пространство от -1 до 1, принимая во внимание расстояние от «камеры» и все остальное.(На самом деле он может выходить за эти границы, но это просто означает, что он находится вне камеры.) Это то, что заставляет наши 3D-сцены выглядеть трехмерными.

Однако возможно также создать матрицу проекции специально для рисования 2D-геометрии.Это называется орфографической матрицей, и установка обычно выглядит примерно так:

var left = 0;
var top = 0;
var right = canvas.width;
var bottom = canvas.height;
var near = 1.0;
var far = 1024.0;
var projectionMat = mat4.ortho(left, right, bottom, top, near, far);

Эта матрица отличается от матрицы перспективы тем, что она полностью игнорирует компонент z вашей позиции.Вместо этого эта матрица преобразует плоские координаты, например пиксели, в диапазон от -1 до 1.Таким образом, ваши сцены не выглядят трехмерными, но легче точно контролировать, где что-то появляется на экране.Таким образом, используя матрицу выше, если мы дадим ей вершину в (16, 16, 0), она появится в (16, 16) на нашем холсте (при условии, что область просмотра имеет те же размеры, что и холст).Таким образом, когда вы хотите рисовать такие вещи, как плоские элементы пользовательского интерфейса, вам нужен именно такой тип матрицы!

Приятная часть в том, что, поскольку это просто значения, которые вы передаете шейдеру, вы можете использовать совершенно разные матрицы.от одного розыгрыша до следующего.Обычно вы рисуете всю свою трехмерную геометрию с помощью матрицы перспективы, а затем весь свой пользовательский интерфейс с ортогональной матрицей.

Извинения, если это было немного бессмысленно.Я никогда не был очень хорош в объяснении всего этого математического материала.

1 голос
/ 25 января 2012

См. http://games.greggman.com/game/webgl-fundamentals

Обычно, если вы хотите рисовать в 2D, используйте 2D шейдер, не пытайтесь связываться с 3D шейдером.

WebGL рисует в пространстве клипа, поэтому все, что вам нужно сделать, - это преобразовать пиксели в пространство клипа.

attribute vec2 a_position;

uniform vec2 u_resolution;

void main() {
   // convert positions from pixels to 0.0 to 1.0
   vec2 zeroToOne = a_position / u_resolution;

   // convert from 0->1 to 0->2
   vec2 zeroToTwo = zeroToOne * 2.0;

   // convert from 0->2 to -1->+1 (clipspace)
   vec2 clipSpace = zeroToTwo - 1.0;

   gl_Position = vec4(clipSpace * vec2(1, -1), 0, 1);
}
1 голос
/ 24 января 2012

Я пытаюсь найти «левую» границу моего порта просмотра WebGL, потому что я хотел бы нарисовать там отладочную информацию. (мини-карта оси, как у большинства программ моделирования) Я, конечно, могу получить ширину и высоту холста, содержащего область просмотра WebGL.

Просто переключите область просмотра и проекцию для этих частей. Вы можете изменить их в любое время.

0 голосов
/ 30 января 2012

Почему бы просто не использовать наложенный HTML-код?

<html>
<head>
  <style>
  #container {
    position: relative;
  }
  #debugInfo {
    position: absolute;
    top: 0px;
    left: 0px;
    background-color: rgba(0,0,0,0.7);
    padding: 1em;
    z-index: 2;
    color: white;
  }
  </style>
</head>
<body>
  <div id="container">
    <canvas></canvas>
    <div id="debugInfo">There be info here!</div>
  </div>
</body>
</html>

Затем вы можете обновить его с помощью

 var debugInfo = document.getElementById("debugInfo");
 debugInfo.innerHTML = "some info";
...