webgl/opengl顶点坐标到屏幕坐标转化

转载自:http://www.songho.ca/opengl/gl_transform.html

Overview

Geometric data such as vertex positions and normal vectors are transformed via Vertex Operation and Primitive Assembly operation in OpenGL pipeline before raterization process.

OpenGL vertex transformation

OpenGL vertex transformation

Object Coordinates

It is the local coordinate system of objects and is initial position and orientation of objects before any transform is applied. In order to transform objects, use glRotatef(), glTranslatef(), glScalef().

Eye Coordinates

It is yielded by multiplying GL_MODELVIEW matrix and object coordinates. Objects are transformed from object space to eye space using GL_MODELVIEW matrix in OpenGL. GL_MODELVIEW matrix is a combination of Model and View matrices (

Mview * Mmodel

). Model transform is to convert from object space to world space. And, View transform is to convert from world space to eye space.

OpenGL eye coordinates

Note that there is no separate camera (view) matrix in OpenGL. Therefore, in order to simulate transforming the camera or view, the scene (3D objects and lights) must be transformed with the inverse of the view transformation. In other words, OpenGL defines that the camera is always located at (0, 0, 0) and facing to -Z axis in the eye space coordinates, and cannot be transformed. See more details of GL_MODELVIEW matrix in ModelView Matrix.

Normal vectors are also transformed from object coordinates to eye coordinates for lighting calculation. Note that normals are transformed in different way as vertices do. It is mutiplying the tranpose of the inverse of GL_MODELVIEW matrix by a normal vector. See more details in Normal Vector Transformation.

normal vector transformation

Clip Coordinates

The eye coordinates are now multiplied with GL_PROJECTION matrix, and become the clip coordinates. This GL_PROJECTION matrix defines the viewing volume (frustum); how the vertex data are projected onto the screen (perspective or orthogonal). The reason it is called clip coordinates is that the transformed vertex (x, y, z) is clipped by comparing with ±w.
See more details of GL_PROJECTION matrix in Projection Matrix.

OpenGL clip coordinates

Normalized Device Coordinates (NDC)

It is yielded by dividing the clip coordinates by w. It is called perspective division. It is more like window (screen) coordinates, but has not been translated and scaled to screen pixels yet. The range of values is now normalized from -1 to 1 in all 3 axes.

OpenGL Normalized Device Coordinates

Window Coordinates (Screen Coordinates)

It is yielded by applying normalized device coordinates (NDC) to viewport transformation. The NDC are scaled and translated in order to fit into the rendering screen. The window coordinates finally are passed to the raterization process of OpenGL pipeline to become a fragment. glViewport() command is used to define the rectangle of the rendering area where the final image is mapped. And, glDepthRange() is used to determine the z value of the window coordinates. The window coordinates are computed with the given parameters of the above 2 functions;
glViewport(x, y, w, h);
glDepthRange(n, f);

OpenGL Window Coordinates

The viewport transform formula is simply acquired by the linear relationship between NDC and the window coordinates;


image

OpenGL Transformation Matrix

OpenGL Transform Matrix

OpenGL Transform Matrix

OpenGL uses 4 x 4 matrix for transformations. Notice that 16 elements in the matrix are stored as 1D array in column-major order. You need to transpose this matrix if you want to convert it to the standard convention, row-major format.

OpenGL has 4 different types of matrices; GL_MODELVIEW, GL_PROJECTION, GL_TEXTURE, and GL_COLOR. You can switch the current type by using glMatrixMode() in your code. For example, in order to select GL_MODELVIEW matrix, use glMatrixMode(GL_MODELVIEW).

Model-View Matrix (GL_MODELVIEW)

GL_MODELVIEW matrix combines viewing matrix and modeling matrix into one matrix. In order to transform the view (camera), you need to move whole scene with the inverse transformation. gluLookAt() is particularly used to set viewing transform.

Columns of OpenGL ModelView matrix

4 columns of GL_MODELVIEW matrix

The 3 matrix elements of the rightmost column (m12, m13, m14) are for the translation transformation, glTranslatef(). The element m15 is the homogeneous coordinate. It is specially used for projective transformation.

3 elements sets, (m0, m1, m2), (m4, m5, m6) and (m8, m9, m10) are for Euclidean and affine transformation, such as rotation glRotatef() or scaling glScalef(). Note that these 3 sets are actually representing 3 orthogonal axes;

  • (m0, m1, m2) : +X axis, left vector, (1, 0, 0) by default
  • (m4, m5, m6) : +Y axis, up vector, (0, 1, 0) by default
  • (m8, m9, m10) : +Z axis, forward vector, (0, 0, 1) by default

We can directly construct GL_MODELVIEW matrix from angles or lookat vector without using OpenGL transform functions. Here are some useful codes to build GL_MODELVIEW matrix:

Note that OpenGL performs matrices multiplications in reverse order if multiple transforms are applied to a vertex. For example, If a vertex is transformed by MA first, and transformed by MB second, then OpenGL performs MB x MA first before multiplying the vertex. So, the last transform comes first and the first transform occurs last in your code.

image


// Note that the object will be translated first then rotated
glRotatef(angle, 1, 0, 0);   // rotate object angle degree around X-axis
glTranslatef(x, y, z);       // move object to (x, y, z)
drawObject();

Projection Matrix (GL_PROJECTION)

GL_PROJECTION matrix is used to define the frustum. This frustum determines which objects or portions of objects will be clipped out. Also, it determines how the 3D scene is projected onto the screen. (Please see more details how to construct the projection matrix.)

OpenGL provides 2 functions for GL_PROJECTION transformation. glFrustum() is to produce a perspective projection, and glOrtho() is to produce a orthographic (parallel) projection. Both functions require 6 parameters to specify 6 clipping planes; left, right, bottom, top, near and far planes. 8 vertices of the viewing frustum are shown in the following image.

OpenGL Perspective Frustum

OpenGL Perspective Viewing Frustum

The vertices of the far (back) plane can be simply calculated by the ratio of similar triangles, for example, the left of the far plane is;


image
OpenGL Orthographic Frustum

OpenGL Orthographic Frustum

For orthographic projection, this ratio will be 1, so the left, right, bottom and top values of the far plane will be same as on the near plane.

You may also use gluPerspective() and gluOrtho2D() functions with less number of parameters. gluPerspective() requires only 4 parameters; vertical field of view (FOV), the aspect ratio of width to height and the distances to near and far clipping planes. The equivalent conversion from gluPerspective() to glFrustum() is described in the following code.


// This creates a symmetric frustum.
// It converts to 6 params (l, r, b, t, n, f) for glFrustum()
// from given 4 params (fovy, aspect, near, far)
void makeFrustum(double fovY, double aspectRatio, double front, double back)
{
    const double DEG2RAD = 3.14159265 / 180;

    double tangent = tan(fovY/2 * DEG2RAD);   // tangent of half fovY
    double height = front * tangent;          // half height of near plane
    double width = height * aspectRatio;      // half width of near plane

    // params: left, right, bottom, top, near, far
    glFrustum(-width, width, -height, height, front, back);
}

image

An example of an asymmetric frustum

However, you have to use glFrustum() directly if you need to create a non-symmetrical viewing volume. For example, if you want to render a wide scene into 2 adjoining screens, you can break down the frustum into 2 asymmetric frustums (left and right). Then, render the scene with each frustum.

Texture Matrix (GL_TEXTURE)

Texture coordinates (s, t, r, q) are multiplied by GL_TEXTURE matrix before any texture mapping. By default it is the identity, so texture will be mapped to objects exactly where you assigned the texture coordinates. By modifying GL_TEXTURE, you can slide, rotate, stretch, and shrink the texture.


// rotate texture around X-axis
glMatrixMode(GL_TEXTURE);
glRotatef(angle, 1, 0, 0);

Color Matrix (GL_COLOR)

The color components (r, g, b, a) are multiplied by GL_COLOR matrix. It can be used for color space conversion and color component swaping. GL_COLOR matrix is not commonly used and is required GL_ARB_imaging extension.

Other Matrix Routines

glPushMatrix() :

push the current matrix into the current matrix stack.

glPopMatrix() :

pop the current matrix from the current matrix stack.

glLoadIdentity() :

set the current matrix to the identity matrix.

glLoadMatrix{fd}(m)** :

replace the current matrix with the matrix m.

glLoadTransposeMatrix{fd}(m)** :

replace the current matrix with the row-major ordered matrix m.

glMultMatrix{fd}(m)** :

multiply the current matrix by the matrix m, and update the result to the current matrix.

glMultTransposeMatrix{fd}(m)** :

multiply the current matrix by the row-major ordered matrix m, and update the result to the current matrix.

glGetFloatv(GL_MODELVIEW_MATRIX, m) :

return 16 values of GL_MODELVIEW matrix to m.

Example: ModelView Matrix

Example of OpenGL ModelView Matrix

This demo application shows how to manipulate GL_MODELVIEW matrix by translation and rotation transforms.

Download the source and binary:
(Updated: 2019-12-06)

[
image

matrixModelView.zip](http://www.songho.ca/opengl/files/matrixModelView.zip) (include VS 2015 project)
[

image

matrixModelView_mac.zip](http://www.songho.ca/opengl/files/matrixModelView_mac.zip) (macOS 10.12+, include Xcode v11)

Note that all OpenGL function calls are implemented in ModelGL.h and ModelGL.cpp on both Mac and Windows versions, and these files are identical on both packages (platform independent).

This demo application uses a custom 4x4 matrix class as well as default OpenGL matrix routines in order to specify model and camera transforms. There are 3 of matrix objects defined in ModelGL.cpp; matrixModel, matrixView and matrixModelView. Each matrix stores the pre-computed transformation and passes the matrix elements to OpenGL by using glLoadMatrixf(). The actual drawing routine looks like;


...
glPushMatrix();

// set view matrix for camera transform
glLoadMatrixf(matrixView.get());

// draw the grid at origin before model transform
drawGrid();

// set modelview matrix for both model and view transform
// It transforms from object space to eye space.
glLoadMatrixf(matrixModelView.get());

// draw a teapot after both view and model transforms
drawTeapot();

glPopMatrix();
...

The equivalent code using default OpenGL matrix functions is;


...
glPushMatrix();

// initialze ModelView matrix
glLoadIdentity();

// First, transform the camera (viewing matrix) from world space to eye space
// Notice translation and heading values are negated,
// because we move the whole scene with the inverse of camera transform
// ORDER: translation -> roll -> heading -> pitch
glRotatef(cameraAngle[2], 0, 0, 1);  // roll
glRotatef(-cameraAngle[1], 0, 1, 0); // heading
glRotatef(cameraAngle[0], 1, 0, 0);  // pitch
glTranslatef(-cameraPosition[0], -cameraPosition[1], -cameraPosition[2]);

// draw the grid at origin before model transform
drawGrid();

// transform the object (model matrix)
// The result of GL_MODELVIEW matrix will be:
// ModelView_M = View_M * Model_M
// ORDER: rotZ -> rotY -> rotX -> translation
glTranslatef(modelPosition[0], modelPosition[1], modelPosition[2]);
glRotatef(modelAngle[0], 1, 0, 0);
glRotatef(modelAngle[1], 0, 1, 0);
glRotatef(modelAngle[2], 0, 0, 1);

// draw a teapot with model and view transform together
drawTeapot();

glPopMatrix();
...

Example: Projection Matrix

Example of OpenGL Projection Matrix
Example of OpenGL Projection Matrix

This demo application is to show how to manipulate the projection transformation with 6 parameters; left, right, bottom, top, near and far values.

Download the source and binary:
(Updated: 2019-11-25)

[
image

matrixProjection.zip](http://www.songho.ca/opengl/files/matrixProjection.zip) (include VS 2015 project)
[

image

matrixProjection_mac.zip](http://www.songho.ca/opengl/files/matrixProjection_mac.zip) (macOS 10.12+, include Xcode v11)

Again, ModelGL.h and ModelGL.cpp are exactly same files on both packages (platform independent), and all OpenGL function calls are placed in these files.

ModelGL class has a custom matrix object, matrixProjection, and 2 member functions, setFrustum() and setOrthoFrustum(), which are equivalent to glFrustum() and glOrtho().


///////////////////////////////////////////////////////////////////////////////
// return a perspective frustum with 6 params similar to glFrustum()
// (left, right, bottom, top, near, far)
///////////////////////////////////////////////////////////////////////////////
Matrix4 ModelGL::setFrustum(float l, float r, float b, float t, float n, float f)
{
    Matrix4 matrix;
    matrix[0]  =  2 * n / (r - l);
    matrix[5]  =  2 * n / (t - b);
    matrix[8]  =  (r + l) / (r - l);
    matrix[9]  =  (t + b) / (t - b);
    matrix[10] = -(f + n) / (f - n);
    matrix[11] = -1;
    matrix[14] = -(2 * f * n) / (f - n);
    matrix[15] =  0;
    return matrix;
}

///////////////////////////////////////////////////////////////////////////////
// return a symmetric perspective frustum with 4 params similar to
// gluPerspective() (vertical field of view, aspect ratio, near, far)
///////////////////////////////////////////////////////////////////////////////
Matrix4 ModelGL::setFrustum(float fovY, float aspectRatio, float front, float back)
{
    float tangent = tanf(fovY/2 * DEG2RAD);   // tangent of half fovY
    float height = front * tangent;           // half height of near plane
    float width = height * aspectRatio;       // half width of near plane

    // params: left, right, bottom, top, near, far
    return setFrustum(-width, width, -height, height, front, back);
}

///////////////////////////////////////////////////////////////////////////////
// set a orthographic frustum with 6 params similar to glOrtho()
// (left, right, bottom, top, near, far)
///////////////////////////////////////////////////////////////////////////////
Matrix4 ModelGL::setOrthoFrustum(float l, float r, float b, float t, float n, float f)
{
    Matrix4 matrix;
    matrix[0]  =  2 / (r - l);
    matrix[5]  =  2 / (t - b);
    matrix[10] = -2 / (f - n);
    matrix[12] = -(r + l) / (r - l);
    matrix[13] = -(t + b) / (t - b);
    matrix[14] = -(f + n) / (f - n);
    return matrix;
}
...

// how to pass projection matrx to OpenGL
Matrix4 projectionMatrix = setFrustum(l, r, b, t, n, f);
glMatrixMode(GL_PROJECTION);
glLoadMatrixf(matrixProjection.get());
...

转载自:http://www.songho.ca/opengl/gl_transform.html

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,377评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,390评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,967评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,344评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,441评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,492评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,497评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,274评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,732评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,008评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,184评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,837评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,520评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,156评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,407评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,056评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,074评论 2 352