|
这个系列的第五部分将讲述如何创建一个3D的物体。本实例中是一个具有四个面的三角锥。
为了使我们今后的开发更简单,需要做一些准备。我们需要能够动态地计算缓冲区大小和创建数组。
java代码:
private int _nrOfVertices = 0;
private void initTriangle() {
float[] coords = {
// 坐标
};
_nrOfVertices = coords.length;
float[] colors = {
// 颜色
};
short[] indices = new short[] {
// 索引
};
// float has 4 bytes, coordinate * 4 bytes
ByteBuffer vbb = ByteBuffer.allocateDirect(coords.length * 4);
vbb.order(ByteOrder.nativeOrder());
_vertexBuffer = vbb.asFloatBuffer();
// short has 2 bytes, indices * 2 bytes
ByteBuffer ibb = ByteBuffer.allocateDirect(indices.length * 2);
ibb.order(ByteOrder.nativeOrder());
_indexBuffer = ibb.aSSHortBuffer();
// float has 4 bytes, colors (RGBA) * 4 bytes
ByteBuffer cbb = ByteBuffer.allocateDirect(colors.length * 4);
cbb.order(ByteOrder.nativeOrder());
_colorBuffer = cbb.asFloatBuffer();
_vertexBuffer.put(coords);
_indexBuffer.put(indices);
_colorBuffer.put(colors);
_vertexBuffer.position(0);
_indexBuffer.position(0);
_colorBuffer.position(0);
}
复制代码
为了更动态一些,我们需要改变一些变量:
在第一行可以看到我们给_nrOfVertices的初值为0因为它的值取决于第七行坐标数组的大小。另外我们将成员变量_indiceArray改为局部变量,该局部变量叫做indices,在第十三行初始化。
缓冲区的创建移到了坐标数组,颜色数组和索引数组下面,因为缓冲区的大小依赖于这些数组的大小。请阅读相关的第17~18行,第22~23行,第27~28行,在注释中我解释清楚了其中的数学表示含义。
这样修改的好处是,我们可以创建更多的顶点而不必手动来修改关于顶点数量,数组和缓冲区大小等值。
下一步,你必须理解OpenGL是如何绘制我们所看到的图形的。OpenGL ES相比OpenGL的一个缺陷就是它只支持三角形。因此为了创建多边形我们必须由三角形来搭建。
现在我们想要创建一个多彩的三角锥,首先需要使依赖我们触摸事件的glClearColor()函数不再工作。因此我们需要移除变量_red, _green, _blue以及setColor()函数。
我们也要改变转动的方向,因此我们把旋转分解到x,y两个轴上。
java代码:
public class VortexRenderer implements GLSurfaceView.Renderer {
private static final String LOG_TAG = VortexRenderer.class.getSimpleName();
// 一个缓冲区来保存绘图顶点的索引值
private ShortBuffer _indexBuffer;
// 一个缓冲区来保存顶点坐标
private FloatBuffer _vertexBuffer;
// 一个缓冲区来存储颜色
private FloatBuffer _colorBuffer;
private int _nrOfVertices = 0;
private float _xAngle;
private float _yAngle;
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
// code snipped
}
@Override
public void onSurfaceChanged(GL10 gl, int w, int h) {
gl.glViewport(0, 0, w, h);
}
public void setXAngle(float angle) {
_xAngle = angle;
}
public float getXAngle() {
return _xAngle;
}
public void setYAngle(float angle) {
_yAngle = angle;
}
public float getYAngle() {
return _yAngle;
}
// code snipped
复制代码
确保你的工程中有与我在类的开始定义的相同名称的变量。这里有两个float型变量来记录角度,xAngle,和_yAngle以及它们相应的设置函数以及获取函数。
java代码:
// code snipped
private float _x = 0;
private float _y = 0;
// code snipped
public boolean onTouchEvent(final MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
_x = event.getX();
_y = event.getY();
}
if (event.getAction() == MotionEvent.ACTION_MOVE) {
final float xdiff = (_x - event.getX());
final float ydiff = (_y - event.getY());
queueEvent(new Runnable() {
public void run() {
_renderer.setXAngle(_renderer.getXAngle() + ydiff);
_renderer.setYAngle(_renderer.getYAngle() + xdiff);
}
});
_x = event.getX();
_y = event.getY();
}
return true;
}
复制代码
当ACTION_DOWN事件发生时我们会设置它们的值,所以一旦我们在屏幕上移动手指,当前坐标与之前坐标的差值会计算出来。之后把这个差值添加到我们对象的角度变量中。第18~19行,你可以想象到,如果我们打算在x方向移动手指时物体会转动,那么它应该是围绕y轴进行旋转。在y方向移动手指,那么它应该是围绕x轴进行旋转。
如果我们将手指移动到最左边或最上边,xdiff或者ydiff的值会是负值因此旋转会是逆向的。到此为止我们已经可以轻松是想2个坐标轴的旋转了。
下面是最有趣的部分:三角锥。
正如我们上面引用的那一部分所提到的一样,围绕(winding)需要一些设置。一些可能是默认的,但是我们仍然对它们进行设置以保证每个方面都按我们设想的进行。
java代码:
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
// preparation
// 保证多边形只有一面可以被观察到
gl.glEnable(GL10.GL_CULL_FACE);
// 决定可以被观察到的那一面的顶点的绘制顺序(逆时针)
gl.glFrontFace(GL10.GL_CCW);
// 哪一面不用被观察到
gl.glCullFace(GL10.GL_BACK);
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
gl.glEnableClientState(GL10.GL_COLOR_ARRAY);
initTriangle();
}
复制代码
在第5行我们使能culling face以便总是显示一个面。在第7行我们定义前面(front)的绘图顶点顺序。设置为GL_CCW就意味着逆时针顺序。在第9行,我们定义哪一面为cull face,即不可以被观察到。我们设置为GL10.GL_BACK,这样前面就可以显示出来。可能有些混乱,如果你尝试用GL_FRONT_AND_BACK就可以看到什么都不会显示出来。
java代码:
@Override
public void onDrawFrame(GL10 gl) {
// 定义背景颜色
gl.glClearColor(0f, 0f, 0f, 1.0f);
// 重置矩阵
gl.glLoadIdentity();
//清除颜色缓冲区
gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
// 设置旋转
gl.glRotatef(_xAngle, 1f, 0f, 0f);
gl.glRotatef(_yAngle, 0f, 1f, 0f);
//gl.glColor4f(0.5f, 0f, 0f, 0.5f);
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, _vertexBuffer);
gl.glColorPointer(4, GL10.GL_FLOAT, 0, _colorBuffer);
gl.glDrawElements(GL10.GL_TRIANGLES, _nrOfVertices, GL10.GL_UNSIGNED_SHORT, _indexBuffer);
}
复制代码
在第4行你可以看到我们的背景颜色是黑色的。在第13~14行是实现旋转的部分。剩下的部分和之前的部分类似。
最后一个需要改动就是initTriangle()函数中的颜色数组,坐标数组以及索引数组。我们的三角锥是这样的:
java代码:
private void initTriangle() {
float[] coords = {
-0.5f, -0.5f, 0.5f, // 0
0.5f, -0.5f, 0.5f, // 1
0f, -0.5f, -0.5f, // 2
0f, 0.5f, 0f, // 3
};
_nrOfVertices = coords.length;
float[] colors = {
1f, 0f, 0f, 1f, // point 0 red
0f, 1f, 0f, 1f, // point 1 green
0f, 0f, 1f, 1f, // point 2 blue
1f, 1f, 1f, 1f, // point 3 white
};
short[] indices = new short[] {
0, 1, 3, // rwg
0, 2, 1, // rbg
0, 3, 2, // rbw
1, 2, 3, // bwg
};
//code snipped
}
复制代码
系列之Android 游戏教程(一)的帖子链接http://www.eoeandroid.com/thread-102096-1-1.html
系列之Android 游戏教程(二)的帖子链接http://www.eoeandroid.com/thread-102097-1-1.html
系列之Android 游戏教程(三)的帖子链接http://www.eoeandroid.com/thread-102100-1-1.html
系列之Android 游戏教程(四)的帖子链接http://www.eoeandroid.com/thread-103115-1-1.html
系列之Android 游戏教程(六)的帖子链接http://www.eoeandroid.com/thread-103121-1-1.html
系列之Android 游戏教程(七)的帖子链接http://www.eoeandroid.com/thread-103125-1-1.html |
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有帐号?立即注册
x
|