您的位置:首页 > 移动开发 > Android开发

Android OpenGL ES教程 第二部分 构建多边形

2014-01-17 11:13 465 查看
原文地址:Android OpenGL ES教程 第二部分 构建多边形
原文作者:leonlee723

OpenGL ES Tutorial for Android – Part II – Building a polygon

Android OpenGL ES教程 第二部分 构建多边形

Previous tutorial was all about setting up the GLSurfaceView. Besure to read it beacuse it's a really importent one to be able tocontinue.

上一课是关于建立GLSurfaceView,请确认你已经看过了,因为这对你继续学习这一课是非常重要

Building a polygon

In this tutorial we will render our first polygon.

建立一个多行形

在这个课里,我们将渲染我们第一个多边形

3D models are built up with smaller elements (vertices, edges,faces, and polygons) which can be manipulated individually.

3D模型是被一个更小的能被单独运用的元素(顶点、边、面、多边型)组成的

Vertex

顶点

A vertex (vertices in plural) is the smallest building block of 3Dmodel. A vertex is a point where two or more edges meet. In a 3Dmodel a vertex can be shared between all connected edges, paces andpolygons. A vertex can also be a represent for the position
of acamera or a light source. You can see a vertex in the image belowmarked in yellow.

顶点是一个3D模型最小的组成单元。一个顶上是二条边或多条边交会的一个点。在一个3D模型里一个顶点能够所有与之有连接的边、paces(不知怎么翻译)、多边形同享。一个顶点也能被表现为一个摄像机或光源的位置。你能看到一个顶点(黄色的点)在图片里。

图1


X

To define the vertices on android we define them as a float arraythat we put into a byte buffer to gain better performance. Look atthe image to the right and the code below to match the verticesmarked on the image to the code.

在android里,我们把顶点定义为一个float的数组,我们为了获得更好的性能将这个数组放到一个byte的buffer里。下面的代码运行结果就是图片,注意标注的顶点。(估计大概是这个意思)



图2

private float vertices[] = {

-1.0f, 1.0f, 0.0f, // 0, Top Left

-1.0f, -1.0f, 0.0f, // 1, Bottom Left

1.0f, -1.0f, 0.0f, // 2, Bottom Right

1.0f, 1.0f, 0.0f, // 3, Top Right

};

// a float is 4 bytes, therefore we multiply the number if verticeswith 4.

ByteBuffer vbb = ByteBuffer.allocateDirect(vertices.length *4);

vbb.order(ByteOrder.nativeOrder());

FloatBuffer vertexBuffer = vbb.asFloatBuffer();

vertexBuffer.put(vertices);

vertexBuffer.position(0);

Don't forget that a float is 4 bytes and to multiply it with thenumber of vertices to get the right size on the allocatedbuffer.

不要忘记了一个 float是4个字节,在分配空间是要把顶点的数量乘以4才是buffer的正确的大小

OpenGL ES have a pipeline with functions to apply when you tell itto render. Most of these functions are not enabled by default soyou have to remember to turn the ones you like to use on. You mightalso need to tell these functions what to work with. So in the
caseof our vertices we need to tell OpenGL ES that it’s okay to workwith the vertex buffer we created we also need to tell where it is.

OpenGLES有一个通道功能用来适应顶点数据的类型当你让它渲染时。更多的情况下,这个功能是默认不启用的,所以你一定要记住去设置为你喜欢的形式。你也可以在你准备要开始工作时再设置。所以在我们的例子里,我们在创建buffer时,我们设置OpenGLES的顶点类型。(不太顺,应该大概是这个意思,哪位能帮忙再顺一下)

// Enabled the vertex buffer for writing and to be used duringrendering.

gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);// OpenGL docs.

// Specifies the location and data format of an array ofvertex

// coordinates to use when rendering.

gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer); // OpenGLdocs.

When you are done with the buffer don't forget to disable it.

当你完成时,不要忘记关掉它

// Disable the vertices buffer.

gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);// OpenGL docs.

Edge



Edge is a line between two vertices. They are border lines of facesand polygons. In a 3D model an edge can be shared between twoadjacent faces or polygons. Transforming an edge affects allconnected vertices, faces and polygons. In OpenGL ES you don't define
theedges, you rather define the face by giving them the vertices thatwould build up the three edges. If you would like modify an edgeyou change the two vertices that makes the edge. You can see anedge in the image below marked in yellow.

边是一个在两个顶点之间的线。他们是一个面或多边形的边框。在一个3D模型里,一个边能被相邻的两个面或多边形共享。改变一个边会影响到所有与之相联系的顶点、面、多边形。在OpenGLES里,你不能定义边,你只能通过定义顶点来定义一个面的三条边。如果你要改变一个条边,那么你去改变定义这条边的两个顶点。下面的图里已经标黄了一条边

Face

Face is a triangle. Face is a surface between three corner verticesand three surrounding edges. Transforming a face affects allconnected vertices, edges and polygons.

在OpenGLES里,一个面是一个三角型。一个面是三个角的顶点和三条围绕边之间的表面。改变一个变将影响所有关联的顶点和边和多边形。

The order does matter.

When winding up the faces it's important to do it in the rightdirection because the direction defines what side will be the frontface and what side will be the back face. Why this is important isbecause to gain performance we don't want to draw both sides so
we turn off the back face. So it's a good idea to usethe same winding all over your project. It is possible to changewhat direction that defines the front face with glFrontFace.

当绘制面时,正确的方法是非常重要的,因为这个方法定义了哪个是面的前部,哪个是面的后部。为什么这个是很重要呢。因为我们不需要同时绘制前后两个部分,所以我们关掉绘制后部,这样可以获得好的性能。所以在你的项目里同样的地方使用这个方法是很好的。当然改变这个方式,可以用glFrontFace来定义前部。也是有可能的。

gl.glFrontFace(GL10.GL_CCW); // OpenGL docs

To make OpenGL skip the faces that are turned into the screen youcan use something called back-face culling. What is does isdetermines whether a polygon of a graphical object is visible bychecking if the face is wind up in the right order.

gl.glEnable(GL10.GL_CULL_FACE); // OpenGL docs

It's of cource possible to change what face side should be drawn ornot.

gl.glCullFace(GL10.GL_BACK); // OpenGL docs

Polygon

多边形

Time to wind the faces, remember we have decided to go with thedefault winding meaning counter-clockwise. Look at the image to theright and the code belowto see how to wind up this square.

在绘制面以后,请记住,我们已经决定使用默认的绘制方式,也就是逆时针方向。看一下图片和代码,我们将演示如何绘制一个正方形

private short[] indices = { 0, 1, 2, 0, 2, 3 };

To gain some performance we also put this ones in a bytebuffer.

// short is 2 bytes, therefore we multiply the number if verticeswith 2.

ByteBuffer ibb = ByteBuffer.allocateDirect(indices.length *2);

ibb.order(ByteOrder.nativeOrder());

ShortBuffer indexBuffer = ibb.asShortBuffer();

indexBuffer.put(indices);

indexBuffer.position(0);

Don't forget that a short is 2 bytes and to multiply it with thenumber of indices to get the right size on the allocatedbuffer.

不要忘记short是两个字节,分配空间时要数组长度乘以2

Render

Time to get something on the screen, there is two functions used to draw and we have to decide which one to use.

是时候在屏幕上做点什么了。这有两个方法来在绘制屏幕,我们必须从中选择一个

The two functions are:

public abstract void glDrawArrays(int mode, int first, int count)// OpenGL docs

glDrawArrays draws the vertices in that order they are specified inthe construction of our verticesBuffer.

glDrawArrays绘制根据顶点buffer里的结构(译者觉得应该是数据)精确的绘制

public abstract void glDrawElements(int mode, int count, int type,// OpenGL docs

Buffer indices)

glDrawElements need a little bit more to be able to draw. It needsto know the order which to draw the vertices, it needs theindicesBuffer.

glDrawElements需要在绘制之前还需要其他的东西。它需要知道绘制顶点的顺序,需要一个索引顺序的buffer

Since we already created the indicesBuffer I'm guessing that youfigured out that's the way we are going.

因为我们已经创建了一个indicesBuffer。我猜你已经知道我将会使用那个方法

What is common for this functions is that they both need to knowwhat it is they should draw, what primitives to render. Since there is some various ways to render this indices andsome of them are good to know about for debugging reasons. I'll gothrough them
all.

这个方法的需要知道的他们应该最先绘制的是什么。因为很多种方法可以渲染这个顶点的索引并且他对知道关于调试的原因是有好处的。我将分析每一个方法

What primitives to render

渲染的索引方法

GL_POINTS

Draws individual points on the screen.

在屏幕上画单独的点

GL_LINE_STRIP

Series of connected line segment

绘制一系统的单独点到点之间的连接线

GL_LINE_LOOP

Same as above, with a segment added between last and first vertices.

和之前的方法一样,只是将最后一个顶点和第一个顶点之间再绘制一个连接线

GL_LINES

Pairs of vertices interpreted as individual line segments.

成对的顶点之间单独绘制线

GL_TRIANGLES

Triples of vertices interpreted as triangles.

每三个顶之间绘制三角形,之间不连接

GL_TRIANGLE_STRIP

Draws a series of triangles (three-sided polygons) using verticesv0, v1, v2, then v2, v1, v3 (note the order), then v2, v3, v4, andso on. The ordering is to ensure that the triangles are all drawnwith the same orientation so that the strip can correctly form
partof a surface.

顺序在每三个顶点之间均绘制三角形。这个方法可以保证从相同的方向上所有以三角形均被绘制。

GL_TRIANGLE_FAN

Same as GL_TRIANGLE_STRIP, except that the vertices are drawn v0,v1, v2, then v0, v2, v3, then v0, v3, v4, and so on.

和GL_TRIANGLE_STRIP一样,除了它是让第一个顶点和以之后的每个顶点绘制三角形

I think the GL_TRIANGLES is the easiest to use so we go with thatone for now.

我想GL_TRIANGLES是最容易用的,所以我们现在就使用它

Putting it all togetter

So let's putting our square together in a class.

package se.jayway.opengl.tutorial;

import java.nio.ByteBuffer;

import java.nio.ByteOrder;

import java.nio.FloatBuffer;

import java.nio.ShortBuffer;

import javax.microedition.khronos.opengles.GL10;

public class Square {

// Our vertices.

private float vertices[] = {

-1.0f, 1.0f, 0.0f, // 0, Top Left

-1.0f, -1.0f, 0.0f, // 1, Bottom Left

1.0f, -1.0f, 0.0f, // 2, Bottom Right

1.0f, 1.0f, 0.0f, // 3, Top Right

};

// The order we like to connect them.

private short[] indices = { 0, 1, 2, 0, 2, 3 };

// Our vertex buffer.

private FloatBuffer vertexBuffer;

// Our index buffer.

private ShortBuffer indexBuffer;

public Square() {

// a float is 4 bytes, therefore we multiply the number if

// vertices with 4.

ByteBuffer vbb = ByteBuffer.allocateDirect(vertices.length *4);

vbb.order(ByteOrder.nativeOrder());

vertexBuffer = vbb.asFloatBuffer();

vertexBuffer.put(vertices);

vertexBuffer.position(0);

// short is 2 bytes, therefore we multiply the number if

// vertices with 2.

ByteBuffer ibb = ByteBuffer.allocateDirect(indices.length *2);

ibb.order(ByteOrder.nativeOrder());

indexBuffer = ibb.asShortBuffer();

indexBuffer.put(indices);

indexBuffer.position(0);

}

public void draw(GL10 gl) {

// Counter-clockwise winding.

gl.glFrontFace(GL10.GL_CCW); // OpenGL docs

// Enable face culling.

gl.glEnable(GL10.GL_CULL_FACE); // OpenGL docs

// What faces to remove with the face culling.

gl.glCullFace(GL10.GL_BACK); // OpenGL docs

// Enabled the vertices buffer for writing and to be usedduring

// rendering.

gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);// OpenGL docs.

// Specifies the location and data format of an array ofvertex

// coordinates to use when rendering.

gl.glVertexPointer(3, GL10.GL_FLOAT, 0, // OpenGL docs

vertexBuffer);

gl.glDrawElements(GL10.GL_TRIANGLES, indices.length,// OpenGLdocs

GL10.GL_UNSIGNED_SHORT, indexBuffer);

// Disable the vertices buffer.

gl.glDisableClientState(GL10.GL_VERTEX_ARRAY); // OpenGL docs

// Disable face culling.

gl.glDisable(GL10.GL_CULL_FACE); // OpenGL docs

}

}

We have to initialize our square in the OpenGLRenderer class.

// Initialize our square.

Square square = new Square();

And in the draw function call on the square to draw.

public void onDrawFrame(GL10 gl) {

// Clears the screen and depth buffer.

gl.glClear(GL10.GL_COLOR_BUFFER_BIT | // OpenGL docs.

GL10.GL_DEPTH_BUFFER_BIT);

// Draw our square.

square.draw(gl); // ( NEW )

}

If you run the application now the screen is still black. Why?Because OpenGL ES render from where the current position is, thatby default is at point: 0, 0, 0 the same position that the viewport is located. And OpenGL ES don’t render the things that are tooclose
to the view port. The solution to this is to move the drawposition a few steps into the screen before rendering thesquare:

如果你运行这个应用,现在屏幕还是黑的。为什么呢?因为OpenGLES渲染是来自于当前的默认的位置,这个位置的点坐标是0,0,0,同时这个点已经被view port给占了。并且OpenGLES不渲染那些离view port太近的点。解决方案是移动这个绘制的位置几步在渲染之前。

// Translates 4 units into the screen.

gl.glTranslatef(0, 0, -4); // OpenGL docs

I will talk about the different transformations in the nexttutorial.

我将在下一课里讲关于这个位置改变的内容

Run the application again and you will see that the square is drawnbut quickly moves further and further into the screen. OpenGL ESdoesn’t reset the drawing point between the frames that you willhave to do yourself:

再次运行这个应用,你将看到这个正方形已经被绘制出来,但是很快的移动。OpenGLES并不会处理两帧之间正在处理的点,所以你需要自己处理。

(译者:在译者的开发环境里,如果注掉以下这句还是什么都显示不出来,不知道问题在哪了。)

// Replace the current matrix with the identity matrix

gl.glLoadIdentity(); // OpenGL docs

Now if you run the application you will see the square on a fixedposition.

现在如果你运行这个应该,你将看到在一个固定位置上的正方形。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: