Draw a three-dimensional, multi-colored, moving cube
Hello! I'm trying to draw a three-dimensional, multi-colored, moving cube. But it turns out that (GL_TRIANGLES_FAN):
(GL_TRIANGLE_STRIP)
As I understand it: we define the coordinates of the vertices of the shape, specify the indexes and colors.
All this is driven into ByteBuffer
, in this case, we determine how much memory we need.
And in the onDrawFrame
method:
We specify the initial position of the figure on the stage:
gl.glTranslatef(0, 0, -5);
Specify the method that will be used for to build triangles:
gl.glDrawArrays(GL10.GL_TRIANGLE_FAN, 0, cube.length);
GL_TRIANGLE _FAN-Triangles are defined by the first and each subsequent pair of vertices (the pairs do not intersect). Here... The usual 2d square I got. Tell me where I went wrong.
public class Renderer implements GLSurfaceView.Renderer {
@Override
public void onSurfaceCreated(GL10 gl10, EGLConfig eglConfig) {
}
@Override
public void onSurfaceChanged(GL10 gl, int i, int i2) {
gl.glViewport(0, 0, i, i2);
float ratio = (float) i / i2;
gl.glMatrixMode(GL10.GL_PROJECTION);
gl.glLoadIdentity();
gl.glFrustumf(-ratio, ratio, -1, 1, 1, 10);
}
/**
* Vertices coordinates
*/
float [] cube = {
0, 0, -1, // A
1, 0, -1, // B
1, 0, 1, // C
0, 0, 1, // D
0, 1, -1, // E
1, 1, -1, // F
1, 1, 1, // G
0, 1, 1 // H
};
float colors[] = {
0, 0, 0, 1, //0 black
1, 0, 0, 1, //1 red
1, 1, 0, 1, //2 yellow
0, 1, 0, 1, //3 green
0, 0, 1, 1, //4 blue
1, 0, 1, 1, //5 magneta
1, 1, 1, 1, //6 white
0, 1, 1, 1, //7 cyan
};
byte [] index = {0,4,5,
1,5,6,
2,6,7,
3,7,4,
4,7,6,
3,0,1
};
FloatBuffer cubeBuffer;
FloatBuffer colorBuffer;
ByteBuffer indexBuffer;
public Renderer() {
ByteBuffer bb1 = ByteBuffer.allocateDirect(cube.length*4);
bb1.order(ByteOrder.nativeOrder());
cubeBuffer = bb1.asFloatBuffer();
cubeBuffer.put(cube);
cubeBuffer.position(0);
ByteBuffer cb = ByteBuffer.allocateDirect(colors.length*4);
cb.order(ByteOrder.nativeOrder());
colorBuffer = cb.asFloatBuffer();
colorBuffer.put(colors);
colorBuffer.position(0);
indexBuffer = ByteBuffer.allocateDirect(index.length*4);
indexBuffer.put(index);
indexBuffer.position(0);
}
@Override
public void onDrawFrame(GL10 gl) {
gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
gl.glMatrixMode(GL10.GL_MODELVIEW);
gl.glLoadIdentity();
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
gl.glEnableClientState(GL10.GL_COLOR_ARRAY);
gl.glColor4f(1, 0, 0, 1);
gl.glColorPointer(4, GL10.GL_FLOAT, 0, colorBuffer);
gl.glTranslatef(0, 0, -5);
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, cubeBuffer);
//gl.glDrawElements(GL10.GL_TRIANGLE_STRIP, index.length, GL10.GL_UNSIGNED_BYTE, indexBuffer);
gl.glDrawArrays(GL10.GL_TRIANGLE_FAN, 0, cube.length);
gl.glRotatef(1, 0.0f, 1.0f, 0.0f);
}
2 answers
Very decent article for beginners on OpenGL ES2 http://dedfox.com/izuchaem-opengl-es2-pod-android-urok-1-samoe-nachalo/
Minimal (you can remove the ES2 support check for even more minimalism) framework for this article typed, just initializing OpenGL ES2 with GLSurfaceView rendering with a gray background:
MainActivity.java
import android.app.Activity;
import android.app.ActivityManager;
import android.content.Context;
import android.content.pm.ConfigurationInfo;
import android.os.Bundle;
import android.opengl.GLSurfaceView;
public class MainActivity extends Activity
{
private GLSurfaceView mGLSurfaceView;
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
mGLSurfaceView = new GLSurfaceView(this);
// Проверка поддержки OpenGL ES2 устройством
ActivityManager am = (ActivityManager)getSystemService(Context.ACTIVITY_SERVICE);
ConfigurationInfo ci = am.getDeviceConfigurationInfo();
// 0х20000 - старшие 16 бит обозначают первое число версии, младшие второе (2.0)
if(ci.reqGlEsVersion < 0x20000)
{
this.finish();
}
// Установим контекст OpenGL ES2
mGLSurfaceView.setEGLContextClientVersion(2);
// Установим рендерер
mGLSurfaceView.setRenderer(new MyRenderer());
setContentView(mGLSurfaceView);
}
@Override
protected void onResume()
{
super.onResume();
mGLSurfaceView.onResume();
}
@Override
protected void onPause()
{
super.onPause();
mGLSurfaceView.onPause();
}
}
MyRenderer.java
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
import android.opengl.GLES20;
import android.opengl.GLSurfaceView.Renderer;
public class MyRenderer implements Renderer
{
@Override
public void onDrawFrame(GL10 gl)
{
GLES20.glClear(GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT);
}
@Override
public void onSurfaceChanged(GL10 gl, int width, int height)
{
}
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config)
{
// Устанавливаем фоновый цвет
GLES20.glClearColor(0.5f, 0.5f, 0.5f, 0.5f);
}
}
I'm sorry, I didn't compile the code, and I took a quick look, but the first thing that needs to be corrected is to draw GL_TRIANGLES, not GL_TRIANGLES_STRIP, and even more so GL_TRIANGLES_FAN.
About the modes I would like to tell you in more detail. Suppose you have an index buffer like this: {a, b, c, d, e, f}. So, in the first mode, which you need(GL_TRIANGLES), two triangles are drawn - abc and def. In the second - abc, bcd,cde,def (a kind of chain. It is necessary for optimization.). In the third - abc, acd, ade,aef (fan, that is, the first vertex common to all triangles. Convenient for drawing convex polygons)
PS: I recommend to immediately master OpenGL ES 2.0. It is a little more complicated, but much more flexible, productive and promising(OpenGL ES 3.0 is an extension for 2.0, while 1.0 is practically not used for quite a long time)