II. Positioning---Chapter 4----The Unreal World
Chapter 4. Objects at Rest
Thus far, we have seen very flat things. Namely, a single triangle. Maybe the triangle moved around or had some colors.
This tutorial is all about how to create a realistic world of objects.
这章讲如何创建一个object的真实世界.
The Orthographic Cube tutorial renders a rectangular prism (a 3D rectangle). The dimensions of the prism are 0.5x0.5x1.5, so it is longer in the Z axis by 3x the X and Y.
The code in this tutorial should be familiar, for the most part. We simply draw 12 triangles rather than one. The rectangular faces of the prism are made of 2 triangles, splitting the face along one of the diagonals.
The vertices also have a color. However, the color for the 6 vertices that make up a face is always the same; this gives each face a single, uniform color.
顶点也有颜色,但是,一个面上6个顶点的颜色值总是一样的,这赋给了每个面一个单独的uniform color.
The vertex shader is a combination of things we know. It passes a color through to the fragment stage, but it also takes a vec2 offset uniform that it adds an offset to the X and Y components of the position. The fragment shader simply takes the interpolated color and uses it as the output color.
vertex shader是一个我们所知道things的结合.它将颜色值传递到fragment stage,它也有一个vec2类型的offset用来作用在position数据的X,Y坐标上.fragment shader简单的获得颜色插值并将其用作输出颜色值.
There is one very noteworthy code change, however: the initialization routine. It has a few new functions that need to be discussed.
初始化程序代码中有一个非常值得注意的变化,程序中有几个新函数需要讨论一下.
Example 4.1. Face Culling Initialization
void init() { InitializeProgram(); InitializeVertexBuffer(); glGenVertexArrays(1, &vao); glBindVertexArray(vao); glEnable(GL_CULL_FACE); glCullFace(GL_BACK); glFrontFace(GL_CW); }
The last three lines are new.
The glEnable
function is a multi-purpose tool. There are a lot of binary on/off flags that are part of OpenGL's state. glEnable
is
used to set these flags to the “on” position. Similarly, there is a glDisable
function that sets the flag to “off.”
glEnable()函数开启某些state,glDisable()关闭相应state.
The GL_CULL_FACE
flag, when enabled, tells OpenGL to activate face culling. Up until now, we have been
rendering with face culling off.
Face culling is a useful feature for saving performance. Take our rectangular prism, for example. Pick up a remote control; their general shape is that of a rectangular prism. No matter how you look at it or orient it, you can never see more than 3 sides of it at once. So why bother spending all that fragment processing time drawing the other three sides?
开启
GL_CULL_FACE
flag时,告诉OpenGL激活face
culling.直到现在我们一直是关闭face culling来进行rendering.Face
culling 对于提高性能是一个很有用的特性.
Face culling is a way of telling OpenGL not to draw the sides of an object that you cannot see. It is quite simple, really.
Face culling是告诉OpenGL不要去绘制那些你看不到的object的面.
In window space, after the transform from normalized device coordinates, you have a triangle. Each vertex of that triangle was presented to OpenGL in a specific order. This gives you a way of numbering the vertices of the triangle.
在窗口空间中,当你将归一化后的设备坐标进行transform后,你会得到一个三角形.呈现在OpenGL中的三角形的每个顶点都有一个确定顺序.这给你一个将三角形顶点编号的方法.
No matter what size or shape the triangle is, you can classify the ordering of a triangle in two ways: clockwise or counter-clockwise. That is, if the order of the vertices from 1 to 2 to 3 moves clockwise in a circle, relative to the triangle's center, then the triangle is facing clockwise relative to the viewer. Otherwise, the triangle is counter-clockwise relative to the viewer. This ordering is called the winding order.
Face culling in OpenGL works based on this ordering. Setting this is a two-step process, and is accomplished by the last two statements of the initialization function.
默认情况下,OpenGL中的Face culling为逆时针方向.也可以按两个步骤进行设置,
The glFrontFace
defines which winding order, clockwise or counter-clockwise, is considered to be the “front” side
of the triangle. This function can be given either GL_CW
or GL_CCW
, for clockwise
and counter-clockwise respectively.
glFrontFace()定义了是逆时针还是顺时针方向被认为是三角形的前面.这个函数的两个参数是
GL_CW
和 GL_CCW
,分别表示逆时针和顺时针.
The glCullFace
function defines which side, front or back, gets culled. This can be given GL_BACK
, GL_FRONT
,
or GL_FRONT_AND_BACK
. The latter culls everything, so no triangles are rendered. This can be useful for measuring vertex shader
performance but is less useful for actually drawing anything.
glCullFace
()函数定义了前面和后面中哪一个面会被cull.有三个参数 GL_BACK
, GL_FRONT
,
或者 GL_FRONT_AND_BACK
. 后面的GL_FRONT_AND_BACK参数把所有面都cull了,所以不会绘制任何三角形.这在提高vertex
shader性能上有用,当确实去绘制something时候用处不大.也就是说以下:
glCullFace(GL_FRONT); glFrontFace(GL_CCW); 等同于: glCullFace(GL_BACK); glFrontFace(GL_CW);
The triangle data in the tutorial is specifically ordered so that the clockwise facing of the triangles face out. This prevents the drawing of the rear-facing faces.
So, the image looks like this:
There's something wrong with this. Namely, that it looks like a square.
Pick up a remote control again. Point it directly at your eye and position it so that it is in the center of your vision. You should only be able to see the front panel of the remote.
Now, move it to the right and up, similar to where the square is. You should be able to see the bottom and left side of the remote.
So we should be able to see the bottom and left side of our rectangular prism. But we cannot. Why not?
Think back to how rendering happens. In clip-space, the vertices of the back end of the rectangular prism are directly behind the front end. And when we transform these into window coordinates, the back vertices are still directly behind the front vertices. This is what the rasterizer sees, so this is what the rasterizer renders.
There has to be something that reality is doing that we are not. That something is called “perspective.”