LIBGDX版NEHE OPENGL- 2. Your First Polygon
说是原创,其实都是参考了libgdx wiki里的教程。不过我自己都做过,一点点的打字,一张张图的截下来。
看到太多LIBGDX 2D方面的教程,于是冲动着自己想学点3D方面的东西。毕竟,如果只做2D,用libgdx还不如cocos2d-x来得方便。
假设已经通过 gdx-setup-ui.jar 建好了libgdx的项目,并且import到eclipse中。以下内容实在是太初级,菜鸟可能都有踩两脚的冲动。
我这里看起来是这样的。
通过gdx-setup-ui.jar建立的项目,大体上分为主项目,和android/ios/desktop/html项目。
这个是一个可运行的项目,运行desktop下的Main.java,然后就能得到:
接下来,对这个项目稍做修改:
新建Class: com.kyugao.nehe.NeHeLibgdx extends Game. 删掉原来的com.kyugao.nehe.MyGdxGame. 然后,添上几行代码如下:
package com.kyugao.nehe; import com.badlogic.gdx.Game; import com.badlogic.gdx.graphics.FPSLogger; import com.kyugao.screen.FirstPolygon; public class NeHeLibgdx extends Game { private FPSLogger fpsLogger; @Override public void create() { // TODO Auto-generated method stub setScreen(new FirstPolygon()); fpsLogger = new FPSLogger(); } @Override public void render() { // TODO Auto-generated method stub super.render(); fpsLogger.log(); } }
Game类是ApplicationListener的一个抽象实现,对一个游戏的生命周期做了一个默认的处理,这里,在create方法中,设置好要显示的screen,并且在render方法中开始render就好了。另外加的一个FPSLogger是为了输出FPS信息,这些信息会输出在console里面。
接下来就要定义我们的FirstPolygon screen. 新建一个包,com.kyugao.screen。如果我有坚持下去,每一课都会在这里新添加一个screen.
那第一课的screen就是com.kyugao.screen.FirstPolygon implements Screen.
代码如下:
package com.kyugao.screen; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.Screen; import com.badlogic.gdx.graphics.GL10; import com.badlogic.gdx.graphics.Mesh; import com.badlogic.gdx.graphics.VertexAttribute; import com.badlogic.gdx.graphics.VertexAttributes.Usage; public class FirstPolygon implements Screen { private Mesh triangleMesh; @Override public void render(float delta) { Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT); drawGLScene(); } private boolean drawGLScene() { triangleMesh.render(GL10.GL_TRIANGLES, 0, 3); return true; } @Override public void show() { triangleMesh = new Mesh(true, 3, 3, new VertexAttribute(Usage.Position, 3, "a_position")); triangleMesh.setVertices(new float[] { -0.5f, -0.5f, 0, // point 1 0.5f, -0.5f, 0, // point 2 0, 0.5f, 0 }); // point 3 triangleMesh.setIndices(new short[] { 0, 1, 2 }); } @Override public void hide() { } @Override public void pause() { } @Override public void resume() { } @Override public void dispose() { } @Override public void resize(int width, int height) { } }
screen的方法,这里重写了show()和render().
Screen下面的show方法,会在被Game设置后调用一次, 之后就反复的通过render去绘制画面了。
render方法中:
Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT); // opengl中的清屏函数,在这里,默认的清屏颜色是黑色,所以看到的背景色都是黑的。通过glClearColor可以自定义这个清屏颜色,比如,我们想要红色的背景Gdx.gl.glClearColor(1, 0, 0, 1),那每次render时填充的颜色就是红色。可以提到一下,如果不需要背景颜色变幻,那glClearColor只要一次指定就好,所以可以写在show()里。
在通过glClear清屏之后,调用drawGLScene来画图形。
show方法:
初始化mesh, 关于mesh,iciba翻译是网格,所以很简单的理解,我定义了三个点的,分别如坐标上写的。然后指定了他们的indices(index), 0, 1, 2
再次运行desktop project下面的Main. 可以得到下面这个图形:
一个三角形,一个正方形:
// glTranslatef(-1.5f,0.0f,-6.0f);
// glVertex3f( 0.0f, 1.0f, 0.0f); // Top
// glVertex3f(-1.0f,-1.0f, 0.0f); // Bottom Left
// glVertex3f( 1.0f,-1.0f, 0.0f); // Bottom Right
// glTranslatef(3.0f,0.0f,0.0f);
// glVertex3f(-1.0f, 1.0f, 0.0f); // Top Left
// glVertex3f( 1.0f, 1.0f, 0.0f); // Top Right
// glVertex3f( 1.0f,-1.0f, 0.0f); // Bottom Right
// glVertex3f(-1.0f,-1.0f, 0.0f); // Bottom Left
先计算一下三角形的三个点,glTranslatef 与 三个顶点相加:TOP: -1.5f, 1.0f, -6.0f
BL: -2.5f, -1.0f, -6.0f
BR: -0.5f, -1.0f, -6.0f
然后正方形的:// glTranslatef(-1.5f,0.0f,-6.0f); + // glTranslatef(3.0f,0.0f,0.0f); = glTranslatef(1.5f, 0.0f, -6.0f),于是:
TL: 0.5f, 1.0f, -6.0f
TR: 2.5f, 1.0f, -6.0f
BR: 2.5f, -1.0f, -6.0f
BL: 0.5f, -1.0f, -6.0f
根据计算值,我重新构建了两个mesh,并且修改drawGLScene方法, 如下:
private Mesh triangleMesh, squareMesh; private boolean drawGLScene() { triangleMesh.render(GL10.GL_TRIANGLES, 0, 3); squareMesh.render(GL10.GL_TRIANGLE_STRIP, 0, 4); return true; } @Override public void show() { triangleMesh = new Mesh(true, 3, 3, new VertexAttribute(Usage.Position, 3, "a_position")); squareMesh = new Mesh(true, 4, 4, new VertexAttribute(Usage.Position, 3, "b_position")); triangleMesh.setVertices(new float[] { // -1.5f, 1.0f, -6.0f, // point 1 -2.5f, -1.0f, -6.0f, // point 2 -0.5f, -1.0f, -6.0f }); // point 3 triangleMesh.setIndices(new short[] { 0, 1, 2 }); squareMesh.setVertices(new float[] { 0.5f, -1.0f, -6.0f,// point BL 2.5f, -1.0f, -6.0f,// point BR 0.5f, 1.0f, -6.0f, // point TL 2.5f, 1.0f, -6.0f // point TR }); squareMesh.setIndices(new short[] { 0, 1, 2, 3 }); }可是,当我一运行,屏幕上只有一片黑色,这个就不截图了。
扩展3D空间,将纸,换成取景器Camera:
平面上画图,一张纸就够了,可是在3D空间里,为了更好的观察,我们要用一个照像机:
package com.kyugao.screen; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.Screen; import com.badlogic.gdx.graphics.GL10; import com.badlogic.gdx.graphics.Mesh; import com.badlogic.gdx.graphics.PerspectiveCamera; import com.badlogic.gdx.graphics.VertexAttribute; import com.badlogic.gdx.graphics.VertexAttributes.Usage; public class FirstPolygon implements Screen { private Mesh triangleMesh, squareMesh; private PerspectiveCamera camera; @Override public void render(float delta) { camera.update(); camera.apply(Gdx.graphics.getGL10()); Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT); drawGLScene(); } private boolean drawGLScene() { triangleMesh.render(GL10.GL_TRIANGLES, 0, 3); squareMesh.render(GL10.GL_TRIANGLE_STRIP, 0, 4); return true; } @Override public void show() { triangleMesh = new Mesh(true, 3, 3, new VertexAttribute(Usage.Position, 3, "a_position")); squareMesh = new Mesh(true, 4, 4, new VertexAttribute(Usage.Position, 3, "b_position")); triangleMesh.setVertices(new float[] { // -1.5f, 1.0f, -6.0f, // point 1 -2.5f, -1.0f, -6.0f, // point 2 -0.5f, -1.0f, -6.0f }); // point 3 triangleMesh.setIndices(new short[] { 0, 1, 2 }); squareMesh.setVertices(new float[] { 0.5f, -1.0f, -6.0f,// point BL 2.5f, -1.0f, -6.0f,// point BR 0.5f, 1.0f, -6.0f, // point TL 2.5f, 1.0f, -6.0f // point TR }); squareMesh.setIndices(new short[] { 0, 1, 2, 3 }); } @Override public void hide() { } @Override public void pause() { } @Override public void resume() { } @Override public void dispose() { } @Override public void resize(int width, int height) { float aspectRatio = (float) width / (float) height; camera = new PerspectiveCamera(45, 2f * aspectRatio, 2f); } }上面是Screen的全部代码,主要是添加了一个照相机 camera,形象一点说,是一个取景器。
在窗口大小改变时,就是取景器的大小改变了,新建一个camera, 然后在每一次render时,更新camera属性,重新render画面。
new PerspectiveCamera(45, 2f * aspectRatio, 2f);相机参数:45是角度,如果你的眼睛可以看面前的180度,那就把45改掉。
2f * aspectRatio, 2f,分别是宽与高,在默认情况下,opengl es把窗口定义为, 以中心点为原点,x, y轴的正负方向各单位1的长度。
(from http://code.google.com/p/libgdx)
但是,如果窗口的长与宽比不是1:1,比如,我横向拉伸了窗后,上面的正方形就变成了:
(from http://code.google.com/p/libgdx)
所以,要计算camera的长宽比。最终,运行一下程序,得到了:
第一课结束。